home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / Sample Code / Processes / ProcDoggie2.1b2 / UProcessGuts.p < prev    next >
Encoding:
Text File  |  1997-11-03  |  82.8 KB  |  2,288 lines  |  [TEXT/CWIE]

  1. UNIT UProcessGuts;
  2.  
  3. {-------------------------------------------------------------------------------
  4.     File:        UProcessGuts.p
  5.  
  6.     Contains:    Guts of the ProcDoggie application.
  7.  
  8.     Written by:    Forrest Tanaka
  9.  
  10.     Copyright:    © 1988-1997 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.  
  14.     You may incorporate this sample code into your applications without
  15.     restriction, though the sample code has been provided "AS IS" and the
  16.     responsibility for its operation is 100% yours.  However, what you are
  17.     not permitted to do is to redistribute the source as "DSC Sample Code"
  18.     after having made changes. If you're going to re-distribute the source,
  19.     we require that you make it clear in the source that the code was
  20.     descended from Apple Sample Code, but that you've made changes.
  21. --------------------------------------------------------------------------------
  22. #
  23. #    Process Manager-related code that’s specific to ProcDoggie is contained in
  24. #    this unit.  Mainly, this code handles the user interface aspects of this
  25. #    program that relate to the Process Manager, such as the Process List window,
  26. #    the Process Information windows, and most of the menus.
  27. #
  28. #    The Process List window displays a list of all active processes.  It allows
  29. #    the user to click on one or more of the process names and then use menu
  30. #    commands to operate on those selected processes.
  31. #
  32. #    Process Information windows display information about the selected active
  33. #    processes.  The information includes the process’s name, type, creator, SIZE
  34. #    resource flags, partition size, and free memory availability.
  35. #
  36. #    When the user chooses to launch an application, routines in this unit are
  37. #    called to ask the user what process to launch and optionally what documents
  38. #    to open or print, depending on the current launch mode.
  39. #
  40. #    This unit also maintains the current launch mode.  The launch mode indicates
  41. #    whether the user wants to simply launch an application, launch an application
  42. #    along with documents to open, and launch an application with documents to
  43. #    print.  The launch mode is global for this application, and affects the way
  44. #    the menu commands that launch applications work.
  45. #
  46. -------------------------------------------------------------------------------}
  47. {[j=20/57/1$] Pasmat Options}
  48.  
  49. INTERFACE
  50.  
  51.  
  52. (*******************************************************************************
  53. * Units
  54. *******************************************************************************)
  55.  
  56.     USES
  57.         UProcessUtils
  58.         ;
  59.  
  60.  
  61. (*******************************************************************************
  62. * SetLaunchMode - Set the launch mode
  63. *
  64. * This routine is called to set the launching mode to the mode specified by the
  65. * "newMode" parameter.  A launch mode of "kJustLaunch" simply launches an
  66. * application or desk accessory, "kOpenLaunch" launches an application with one
  67. * or more documents for the launched application to open, "kPrintLaunch"
  68. * launches an application with one or more documents for the launched
  69. * application to print.  The launch modes are declared in UProcessUtils.p.
  70. *******************************************************************************)
  71.  
  72.     PROCEDURE SetLaunchMode (newMode: LaunchModeCode);
  73.  
  74.  
  75. (*******************************************************************************
  76. * GetLaunchMode - Get the launch mode
  77. *
  78. * The current launch mode is returned.  For details about launching modes, see
  79. * the description of the SetLaunchMode routine.
  80. *******************************************************************************)
  81.  
  82.     FUNCTION GetLaunchMode: LaunchModeCode;
  83.  
  84.  
  85. (*******************************************************************************
  86. * IsProcessListWindow - Is a WindowPtr a pointer to a process list window?
  87. *
  88. * When I want to find out whether a window that I have a pointer to is a process
  89. * list window or not, I call this routine.  It returns TRUE if aWindow is a
  90. * pointer to a process list window, FALSE if it isn’t.  If aWindow is NIL, then
  91. * IsProcessListWindow returns FALSE.
  92. *******************************************************************************)
  93.  
  94.     FUNCTION IsProcessListWindow (aWindow: WindowPtr): Boolean;
  95.  
  96.  
  97. (*******************************************************************************
  98. * CreateProcessListWindow - Create a process list window
  99. *
  100. * This routine is called to create a new Process List window visible and
  101. * centered on the main screen.  A pointer to the window is returned.  If there
  102. * isn’t enough memory for the window, or if some other problem happened to make
  103. * it impossible to create the window, then CreateProcessListWindow puts up an
  104. * alert indicating this to the user, and then it returns NIL.
  105. *******************************************************************************)
  106.  
  107.     FUNCTION CreateProcessListWindow: WindowPtr;
  108.  
  109.  
  110. (*******************************************************************************
  111. * IdleProcessListWindow - Keep the process list window up to date
  112. *
  113. * IdleProcessListWindow updates the process list window specified by
  114. * processListWindow so that it reflects the status of the processes that are
  115. * currently open.  It’s called once per main event loop iteration.
  116. *******************************************************************************)
  117.  
  118.     PROCEDURE IdleProcessListWindow (processListWindow: WindowPtr);
  119.  
  120.  
  121. (*******************************************************************************
  122. * DrawProcessListWindow - Draw the contents of the process list window
  123. *
  124. * Whenever an update event is received for the process list window, the routine
  125. * is called to draw into the window.  Since the process list covers the entire
  126. * window, the only thing to be done is to call the List Manager to draw the
  127. * list.  processListWindow is a pointer to the process list window.
  128. *******************************************************************************)
  129.  
  130.     PROCEDURE DrawProcessListWindow (processListWindow: WindowPtr);
  131.  
  132.  
  133. (*******************************************************************************
  134. * ClickProcessListWindow - Handle a mouse click in the process list window
  135. *
  136. * When a mouse click is detected in the content region of the process list
  137. * window specified by processListWindow, this routine is called to handle it.
  138. * It allows the user to select a process or several processes in the list.  If
  139. * the user double-clicks on a process, then that process and any other selected
  140. * processes are brought to the front.
  141. *
  142. * clickEvent is the mouse-down event that was in the process list window.
  143. *******************************************************************************)
  144.  
  145.     PROCEDURE ClickProcessListWindow (processListWindow: WindowPtr;
  146.                                       clickEvent:        EventRecord);
  147.  
  148.  
  149. (*******************************************************************************
  150. * ActivateProcessListWindow - Handle an activate/deactivate event
  151. *
  152. * Whenever an activate or deactivate event is received for the process list
  153. * window specified by processListWindow, this routine is called to handle the
  154. * event.  If the event was an activate event, then becomingActive is TRUE.  If
  155. * the event was a deactivate event, then becomingActive is FALSE.
  156. *******************************************************************************)
  157.  
  158.     PROCEDURE ActivateProcessListWindow (processListWindow: WindowPtr;
  159.                                          becomingActive:    Boolean);
  160.  
  161.  
  162. (*******************************************************************************
  163. * FixProcessListMenus - Undim menu items for process list window
  164. *
  165. * Any menus that should be available when the process list window is in front
  166. * are undimmed if the current conditions are appropriate.
  167. *******************************************************************************)
  168.  
  169.     PROCEDURE FixProcessListMenus (processListWindow: WindowPtr);
  170.  
  171.  
  172. (*******************************************************************************
  173. * IsProcessInfoWindow - Is a WindowPtr a pointer to a process info window?
  174. *
  175. * When I want to find out whether a window that I have a pointer to is a process
  176. * info window or not, I call this routine.  It returns TRUE if aWindow is a
  177. * pointer to a process info window, FALSE if it isn’t.  If aWindow is NIL, then
  178. * IsProcessInfoWindow returns NIL.
  179. *******************************************************************************)
  180.  
  181.     FUNCTION IsProcessInfoWindow (aWindow: WindowPtr): Boolean;
  182.  
  183.  
  184. (*******************************************************************************
  185. * IdleProcessInfoWindow - Give the specified process info window some idle time
  186. *
  187. * This routine is called once per event loop iteration.  It gives the specified
  188. * process info window some idle time to update the memory indicator.
  189. *******************************************************************************)
  190.  
  191.     PROCEDURE IdleProcessInfoWindow (processInfoWindow: WindowPtr);
  192.  
  193.  
  194. (*******************************************************************************
  195. * DrawProcessInfoWindow - Draw the contents of the process info window
  196. *
  197. * Whenever an update event is received for the process info window, the routine
  198. * is called to draw the static items into the window.
  199. *******************************************************************************)
  200.  
  201.     PROCEDURE DrawProcessInfoWindow (processInfoWindow: WindowPtr);
  202.  
  203.  
  204. (*******************************************************************************
  205. * FixProcessInfoMenus - Undim menu items for process information window
  206. *
  207. * Any menus that should be available when a process information window is in
  208. * front are undimmed if the current conditions are appropriate.
  209. *******************************************************************************)
  210.  
  211.     PROCEDURE FixProcessInfoMenus (processInfoWindow: WindowPtr);
  212.  
  213.  
  214. (*******************************************************************************
  215. * DoWindowClose - Window closing bottleneck
  216. *
  217. * As new kinds of windows are added to this application, this routine will have
  218. * to be able to detect the new kind of window and dispatch to the routine that
  219. * handles close requests for that kind of window.
  220. *
  221. * As we only have one kind of window that's closable at the moment
  222. * (process info windows), this routine simply checks whether eventWind is
  223. * such a window, and closes it if it is.
  224. *******************************************************************************)
  225.  
  226.     PROCEDURE DoWindowClose (eventWind: WindowPtr);
  227.  
  228.  
  229. (*******************************************************************************
  230. * IdleAllProcessWindows - Give every open process window idle time
  231. *
  232. * IdleAllProcessWindows is called to give the process list window and all open
  233. * process info windows some idle time.  This routine is called once per main
  234. * event loop iteration.
  235. *******************************************************************************)
  236.  
  237.     PROCEDURE IdleAllProcessWindows;
  238.  
  239.  
  240. (*******************************************************************************
  241. * DoLaunchInFront - Launch a process to the front
  242. *
  243. * When the user wants to launch a process and have it brought to the front, this
  244. * routine is called.  It allows the user to choose a process through Standard
  245. * File.  That application is then launched and brought to the front.
  246. *******************************************************************************)
  247.  
  248.     PROCEDURE DoLaunchInFront;
  249.  
  250.  
  251. (*******************************************************************************
  252. * DoLaunchInBack - Launch a process to the back
  253. *
  254. * When the user wants to launch a process and have it sent to the back of all of
  255. * the open processes, this routine is called.  It allows the user to choose a
  256. * process through Standard File.  That process is then launched and sent to the
  257. * back.
  258. *******************************************************************************)
  259.  
  260.     PROCEDURE DoLaunchInBack;
  261.  
  262.  
  263. (*******************************************************************************
  264. * DoLaunchTo - Launch a process and terminate self
  265. *
  266. * When the user wants to launch a process and then immediately quit ProcDoggie,
  267. * this routine is called.  It allows the user to choose a process through
  268. * Standard File.  That process is then launched and brought to the front, and
  269. * then ProcDoggie is immediately terminated.
  270. *******************************************************************************)
  271.  
  272.     PROCEDURE DoLaunchTo;
  273.  
  274.  
  275. (*******************************************************************************
  276. * DoLaunchMode - Handle Simple Launch, Open on Launch, Print on Launch commands
  277. *
  278. * This routine is called when a launch mode menu item is chosen.  The launch
  279. * mode items are in the file menu and are the “Simple Launch,” “Open Documents
  280. * on Launch,” and “Print Documents on Launch” items.
  281. *******************************************************************************)
  282.  
  283.     PROCEDURE DoLaunchMode (modeItem: Integer);
  284.  
  285.  
  286. (*******************************************************************************
  287. * DoBringProcessToFront - Bring an open process to the front
  288. *
  289. * When the user chooses the Bring to Front menu item, this routine is called to
  290. * bring all the selected process to the front in the order that they appear in
  291. * the process list window specified by processListWindow.  For the moment, it
  292. * won’t bring it’s own application (ProcDoggie) to the front.  I don’t know how
  293. * or whether I’ll be able to fix that.
  294. *******************************************************************************)
  295.  
  296.     PROCEDURE DoBringProcessToFront (processListWindow: WindowPtr);
  297.  
  298.  
  299. (*******************************************************************************
  300. * DoGetProcessInfo - Get information about selected processes
  301. *
  302. * This routine is called when the user desires information about the processes
  303. * selected in the process list window specified by the "processListWindow"
  304. * parameter.
  305. *******************************************************************************)
  306.  
  307.     PROCEDURE DoGetProcessInfo (processListWindow: WindowPtr);
  308.  
  309.  
  310. (*******************************************************************************
  311. * DoTerminateProcess - Terminate the selected processes
  312. *
  313. * This routine is called when the user wants to terminate the processes selected
  314. * in the process list window specified by the "processListWindow" parameter.
  315. *******************************************************************************)
  316.  
  317.     PROCEDURE DoTerminateProcess (processListWindow: WindowPtr);
  318.  
  319.  
  320. (*******************************************************************************
  321. * InitProcessGuts - Initialise this module
  322. *******************************************************************************)
  323.  
  324.     PROCEDURE InitProcessGuts;
  325.  
  326.  
  327. IMPLEMENTATION
  328.  
  329.     uses
  330.         TextUtils
  331.         ,Lists
  332.         ,Fonts
  333.         ,GestaltEqu
  334.         ,Resources
  335.         ,StandardFile
  336.         ,Palettes
  337.         ,LowMem
  338.         ,fp
  339.  
  340.         ,UEmergMem
  341.         ,UDialogUtils
  342.         ,UProcessLDEF        
  343.         ,UMenuHandler
  344.         ;
  345.         
  346.  
  347. (*******************************************************************************
  348. * Constants
  349. *******************************************************************************)
  350.  
  351.     CONST
  352.         rProcessListWindID = 128; {Resource ID of process list window template}
  353.         rProcessInfoWindID = 129; {Resource ID of process info window template}
  354.         rProcessInfoDitlID = 129; {Resource ID of process info dialog item list}
  355.  
  356.         kProcessListWindKind = 8;    {In windowKind field of process list windows}
  357.         kProcessInfoWindKind = 9;    {In windowKind field of process info windows}
  358.         kActivateList        = TRUE; {Pass to LActivate to specify activate list}
  359.         kScrollBarWidth      = 16;   {Width of scroll bar in pixels}
  360.  
  361.         rAppOrDAStringID = 128; {Resource ID of Application or DA string}
  362.         kAppStringInd    = 1;   {Index for Application string}
  363.         kDAStringInd     = 2;   {Index for Desk Accessory string}
  364.  
  365.         rCheckMarkID = 128; {Resource ID of checkmark string}
  366.  
  367.         kProcessNameItem   = 1;  {Dialog item # of process name}
  368.         kAppOrDAItem       = 2;  {Dialog item # of Application/DA string}
  369.         kTotalSizeItem     = 5;  {Dialog item # of Total Size readout}
  370.         kFreeSpaceItem     = 6;  {Dialog item # of Free Space readout}
  371.         kMemIndicatorItem  = 7;  {Dialog item # of partition memory indicator}
  372.         kGrayLineItem0     = 8;  {Dialog item # of first gray line}
  373.         kTypeItem          = 11; {Dialog item # of TYPE item}
  374.         kCreatorItem       = 12; {Dialog item # of Creator item}
  375.         kGrayLineItem1     = 13; {Dialog item # of second gray line}
  376.         kSusResChkItem     = 14; {Dialog item # of suspend/resume checkmark}
  377.         kWindActChkItem    = 15; {Dialog item # of window activate checkmark}
  378.         kGetClickChkItem   = 16; {Dialog item # of Get front click checkmark}
  379.         kAppDiedChkItem    = 17; {Dialog item # of App Died checkmark}
  380.         kStationeryChkItem = 18; {Dialog item # of Stationery checkmark}
  381.         kCanBackChkItem    = 19; {Dialog item # of Can Background checkmark}
  382.         kOnlyBackChkItem   = 20; {Dialog item # of Only Background checkmark}
  383.         kHighLevelChkItem  = 21; {Dialog item # of High-Level Evt checkmark}
  384.         kRHighLevelChkItem = 22; {Dialog item # of Remote High-Level checkmark}
  385.         kMultiUserChkItem  = 23; {Dialog item # of Multi-user Launch checkmark}
  386.         k32BitCleanChkItem = 24; {Dialog item # of 32-Bit Clean checkmark}
  387.         kUseTextEditServicesChkItem = 25; {Dialog item # of Use TextEdit Services checkmark}
  388.         kDisplayManagerAwareChkItem = 26; {Dialog item # of Display Manager Aware checkmark}
  389.  
  390.         kUsedColor = 2; {Process Info window palette color for used memory}
  391.         kFreeColor = 3; {Process Info window palette color for free memory}
  392.  
  393.  
  394. (*******************************************************************************
  395. * Types
  396. *******************************************************************************)
  397.  
  398.     TYPE
  399.         {Pointer to canonical format for number strings}
  400.         NumFormatStringPtr = ^NumFormatString;
  401.  
  402.  
  403. (*******************************************************************************
  404. * Variables
  405. *******************************************************************************)
  406.  
  407.     VAR
  408.         gProcessListLDEF: ListDefUPP;
  409.         gEqualPSNUPP : ListSearchUPP;
  410.         gAppDAFilterUPP: FileFilterUPP;
  411.         
  412.     VAR
  413.         gLaunchMode: LaunchModeCode; {Open documents? Print documents?}
  414.  
  415.  
  416. {$S ProcessGuts}
  417. (*******************************************************************************
  418. * Public: SetLaunchMode
  419. *
  420. * The global variable, "gLaunchMode", is set to the launch mode specified by
  421. * "newMode".
  422. *******************************************************************************)
  423.  
  424.     PROCEDURE SetLaunchMode (newMode: LaunchModeCode);
  425.  
  426.     BEGIN
  427.         gLaunchMode := newMode
  428.     END;
  429.  
  430.  
  431. {$S ProcessGuts}
  432. (*******************************************************************************
  433. * Public: GetLaunchMode
  434. *
  435. * The value of the global variable, "gLaunchMode", is returned.
  436. *******************************************************************************)
  437.  
  438.     FUNCTION GetLaunchMode: LaunchModeCode;
  439.  
  440.     BEGIN
  441.         GetLaunchMode := gLaunchMode
  442.     END;
  443.  
  444.  
  445. {$S Main}
  446. (*******************************************************************************
  447. * Public: IsProcessListWindow
  448. *
  449. * I store a unique code in the windowKind field of every window I create so that
  450. * I can identify the kind of window it is later… like now!  I check to see if
  451. * the windowKind field of aWindow is kProcessListWindKind or not.  If it is, I
  452. * know it’s a process list window, and so IsProcessListWindow returns TRUE.
  453. *******************************************************************************)
  454.  
  455.     FUNCTION IsProcessListWindow (aWindow: WindowPtr): Boolean;
  456.  
  457.     BEGIN
  458.         IF aWindow <> NIL THEN
  459.             IsProcessListWindow := WindowPeek(aWindow)^.windowKind =
  460.                     kProcessListWindKind
  461.         ELSE
  462.             IsProcessListWindow := FALSE
  463.     END;
  464.  
  465.  
  466. {$S ProcessGuts}
  467. (*******************************************************************************
  468. * Public: CreateProcessListWindow
  469. *
  470. * I store the constant kProcessListWindKind into the windowKind field of the new
  471. * window.  When the routine IsProcessListWindow is called, it uses this field to
  472. * identify a window as a process list window.
  473. *
  474. * See the UWindowHandler unit for code to create a new window.
  475. *******************************************************************************)
  476.  
  477.     FUNCTION CreateProcessListWindow: WindowPtr;
  478.  
  479.         CONST
  480.             kDrawList      = TRUE; {Pass to LNew; list must be drawn immediately}
  481.             kHasGrow       = TRUE; {Pass to LNew; list has grow box}
  482.             kHasHorzScroll = TRUE; {Pass to LNew; list has a horizontal scroll bar}
  483.             kHasVertScroll = TRUE; {Pass to LNew; list has a vertical scroll bar}
  484.  
  485.         VAR
  486.             aWindow:        WindowPtr;  {Pointer to the process list window}
  487.             processList:    ListHandle; {Handle to the list of processes}
  488.             listRect:       Rect;       {Rectangle of list in window coords}
  489.             listDimensions: Rect;       {Dimensions of list in cells}
  490.             cellSize:       Point;      {Size of cell in pixels}
  491.             currFont:       FontInfo;   {Information about current port’s font}
  492.  
  493.         PROCEDURE HandleError (messageClass: Integer;
  494.                                messageIndex: Integer);
  495.  
  496.             VAR
  497.                 junkError: OSErr;
  498.                 junkItemHit: Integer; {Result of alert; ignored}
  499.  
  500.         BEGIN
  501.             IF aWindow <> NIL THEN
  502.                 BEGIN
  503.                     CloseWindow (aWindow);
  504.                     DisposePtr (Ptr(aWindow))
  505.                 END;
  506.             junkError := ShowStopAlert (messageClass, messageIndex, junkItemHit);
  507.             gError := noErr;
  508.             CreateProcessListWindow := NIL;
  509.             EXIT (CreateProcessListWindow)
  510.         END;
  511.  
  512.     BEGIN
  513.         aWindow := NIL;
  514.  
  515.         (* Create the new window *)
  516.         aWindow := CreateWindow (rProcessListWindID);
  517.         IF gError <> noErr THEN
  518.             IF gError = memFullErr THEN
  519.                 HandleError (rMemErrMessages, kMemErrProcListOpenMsg)
  520.             ELSE IF gError = resNotFound THEN
  521.                 HandleError (rResErrMessages, kResErrAppDamageMsg)
  522.             ELSE IF gError = dsSysErr THEN
  523.                 HandleError (rMiscErrMessages, kMiscErrUnknownMsg);
  524.  
  525.         (* Set up the window *)
  526.         SetPort (aWindow);
  527.         WindowPeek(aWindow)^.windowKind := kProcessListWindKind;
  528.         TextFont (applFont);
  529.  
  530.         (* Create the process list *)
  531.         GetFontInfo ((*<*)currFont);
  532.         listRect := aWindow^.portRect;
  533.         listRect.right := listRect.right - kScrollBarWidth + 1;
  534.         SetRect ((*<*)listDimensions, 0, 0, 1, 0);
  535.         cellSize.h := listRect.right - listRect.left;
  536.         cellSize.v := currFont.ascent + currFont.descent + currFont.leading;
  537.         processList := LNew (listRect, listDimensions, cellSize, 128, aWindow,
  538.                 kDrawList, NOT kHasGrow, NOT kHasHorzScroll, kHasVertScroll);
  539.         IF FailLowMemory (0) THEN
  540.             HandleError (rMemErrMessages, kMemErrProcListOpenMsg);
  541.  
  542.         (* Install our real LDEF into the refCon so that the stub will call it.*)
  543.         processList^^.refCon := longint(gProcessListLDEF);
  544.         
  545.         (* Make sure the list is activated *)
  546.         LActivate (kActivateList, processList);
  547.  
  548.         (* Save a handle to the list in the refCon of the window *)
  549.         SetWRefCon (aWindow, LongInt (processList));
  550.  
  551.         (* Set the new window as the current GrafPort and return *)
  552.         SetPort (aWindow);
  553.         CreateProcessListWindow := aWindow
  554.     END;
  555.  
  556.  
  557. {$S ProcessGuts}
  558. (*******************************************************************************
  559. * Private: EqualPSN - List Manager search proc
  560. *
  561. * The List Manager’s LSearch function can take a pointer to a routine that
  562. * checks to see if a record matches an entry in the list.  The routine must have
  563. * an interface identical to IUMagIDString.  EqualPSN is the routine that I pass
  564. * to LSearch in the IdleProcessListWindow routine.  It compares the process
  565. * serial number passed in testPSN against the process serial number contained in
  566. * the ProcessListInfoRec of a cell.  Because I already know the lengths of
  567. * ProcessListInfoRecs and ProcessSerialNumber records, I ignore the aLen and
  568. * bLen parameters.
  569. *
  570. * If the two process serial numbers refer to the same process, then EqualPSN
  571. * returns 0, otherwise it returns 1.
  572. *******************************************************************************)
  573.  
  574.     FUNCTION EqualPSN (processInfo: ProcessListInfoPtr;
  575.                        testPSN:     ProcessSerialNumberPtr;
  576.                        aLen:        Integer;
  577.                        bLen:        Integer): Integer;
  578.  
  579.         VAR
  580.             equal: Boolean; {TRUE if PSNs are equal}
  581.             error: OSErr;
  582.  
  583.     BEGIN
  584.         {$unused aLen}
  585.         {$unused bLen}
  586.         error := SameProcess (testPSN^, processInfo^.serialNumber, (*<*)equal);
  587.         IF equal THEN
  588.             EqualPSN := 0
  589.         ELSE
  590.             EqualPSN := 1
  591.     END;
  592.  
  593.  
  594. {$S ProcessGuts}
  595. (*******************************************************************************
  596. * Private: SetProcessListInfo - Set process list cell info
  597. *
  598. * SetProcessListInfo sets the cell specified by row (I’m only using one column,
  599. * so only the row matters) of the list specified by procList to the information
  600. * in procInfo.  My lists contain ProcessListInfoRecs, which contain only two of
  601. * the fields in ProcessInfoRecs (process name and process serial number), so I
  602. * just copy these two fields from procInfo into listInfo.  I then use LSetCell
  603. * to copy listInfo into the list.
  604. *******************************************************************************)
  605.  
  606.     PROCEDURE SetProcessListInfo (procInfo: ProcessInfoRec;
  607.                                   row:      Integer;
  608.                                   procList: ListHandle);
  609.  
  610.         VAR
  611.             listInfo: ProcessListInfoRec; {Process info from List Mgr list}
  612.             newCell:  Cell;               {Cell in which to set information}
  613.  
  614.     BEGIN
  615.         BlockMove (Ptr(procInfo.processName), @listInfo.processName,
  616.                 ORD (procInfo.processName^ [0]) + 1);
  617.  
  618.         (* Copy the process serial number *)
  619.         listInfo.serialNumber := procInfo.processNumber;
  620.  
  621.         (* Set the specified cell to the new ProcessListInfoRec *)
  622.         newCell.h := 0;
  623.         newCell.v := row;
  624.         LSetCell (Ptr(@listInfo), SIZEOF (ProcessListInfoRec), newCell, procList)
  625.     END;
  626.  
  627.  
  628. {$S ProcessGuts}
  629. (*******************************************************************************
  630. * Public: IdleProcessListWindow
  631. *
  632. * I’m using a simple algorithm to keep the process list window’s process list
  633. * updated to the Process Manager’s process list, but it’ll probably be tough to
  634. * describe.  Here goes. . .
  635. *
  636. * I compare the process serial number of each entry in the Process Manager’s
  637. * list against the process serial number of the corresponding entry in
  638. * the process list window’s list.  If they match, then I just go on to the next
  639. * entries of the lists.  If they don’t match, then I search the window’s list in
  640. * case the matching process is farther down.  If I do find it farther down, then
  641. * I assume that the processes in the window’s list that come between the
  642. * matching entries in the two lists were deleted.  So, I delete those rows.  If
  643. * I don’t find it farther down, then I assume that the entry is new.  I then
  644. * insert a new row in the corresponding position of the window’s list and copy
  645. * the process information to it.
  646. *
  647. * If I run out of rows in the window’s list before getting through the entire
  648. * Process Manager list, then I just keep adding new rows to the end of the
  649. * window’s list and copying over the balance.
  650. *
  651. * If I go through the entire Process Manager list but there are left-over
  652. * entries in the window’s list, then I just delete those left-overs.
  653. *
  654. * So, that’s the algorithm.  It was the most efficient one I could come up with
  655. * that wasn’t even harder to explain.  Beware: some parts of this routine have
  656. * only gotten minimal testing, so I wouldn’t be surprised if you find bugs.
  657. *******************************************************************************)
  658.  
  659.     PROCEDURE IdleProcessListWindow (processListWindow: WindowPtr);
  660.  
  661.         VAR
  662.             procNum:        ProcessSerialNumber; {Serial number of open processes}
  663.             procInfo:       ProcessInfoRec;      {Process info from Proc Mgr list}
  664.             procName:       Str255;              {Name of the process}
  665.             listInfo:       ProcessListInfoRec;  {Process info from List Mgr list}
  666.             listInfoLength: Integer;             {Size of ProcessListInfoRec}
  667.             currCell:       Cell;                {List cell being checked}
  668.             matchCell:      Cell;                {Cell with matching PSN}
  669.             procList:       ListHandle;          {Handle to List Mgr process list}
  670.             foundMatch:     Boolean;             {Found matching List Mgr entry}
  671.             equal:          Boolean;             {Proc and List Mgr elements match}
  672.             addedProcess:   Boolean;             {TRUE if a process added to list}
  673.             error:          OSErr;
  674.             junkError:        OSErr;
  675.             junkItemHit:    Integer;             {Result of alert; ignored}
  676.  
  677.     BEGIN
  678.         (* Get the List Manager’s copy of the process list *)
  679.         procList := ListHandle(GetWRefCon (processListWindow));
  680.  
  681.         (* Start checking from start of List Mgr and Process Mgr lists *)
  682.         addedProcess := FALSE;
  683.         currCell.v := 0;
  684.         currCell.h := 0;
  685.         procNum.highLongOfPSN := 0;
  686.         procNum.lowLongOfPSN := kNoProcess;
  687.  
  688.         (* Keep looping through each open process *)
  689.         WHILE GetNextProcess ((*◊*)procNum) = noErr DO
  690.             BEGIN
  691.                 (* Get information about an open process *)
  692.                 procInfo.processInfoLength := SIZEOF (ProcessInfoRec);
  693.                 procInfo.processName := @procName;
  694.                 procInfo.processAppSpec := NIL;
  695.                 error := GetProcessInformation (procNum, (*◊*)procInfo);
  696.  
  697.                 (* Cmp List Mgr & Proc Mgr lists if enuf cells for # of processes *)
  698.                 IF PtInRect (currCell, procList^^.dataBounds) THEN
  699.                     BEGIN
  700.                         (* Get process info from List Mgr list *)
  701.                         listInfoLength := SIZEOF (ProcessListInfoRec);
  702.                         LGetCell ((*<*)@listInfo, (*◊*)listInfoLength, currCell,
  703.                                 procList);
  704.  
  705.                         (* If Proc & List Mgr lists differ, update List Mgr list *)
  706.                         error := SameProcess (procInfo.processNumber, listInfo.
  707.                                 serialNumber, (*<*)equal);
  708.                         IF NOT equal THEN
  709.                             BEGIN
  710.                                 (* See if matching process farther down List Mgr list *)
  711.                                 matchCell := currCell;
  712.                                 foundMatch := LSearch (@procInfo.processNumber,
  713.                                         SIZEOF (ProcessSerialNumber), gEqualPSNUPP,
  714.                                         (*◊*)matchCell, procList);
  715.  
  716.                                 (* Was there a match farther down the List Mgr list? *)
  717.                                 IF foundMatch THEN
  718.                                     (* Yes, delete intervening cells *)
  719.                                     LDelRow (matchCell.v - currCell.v, currCell.v,
  720.                                             procList)
  721.                                 ELSE
  722.                                     (* No, insert the new process into List Mgr list *)
  723.                                     BEGIN
  724.                                         currCell.v := LAddRow (1, currCell.v, procList);
  725.                                         SetProcessListInfo (procInfo, currCell.v,
  726.                                                 procList)
  727.                                     END
  728.                             END
  729.                     END
  730.                 ELSE
  731.                     BEGIN
  732.                         (* Ran out of rows, add one *)
  733.                         currCell.v := LAddRow (1, currCell.v, procList);
  734.                         addedProcess := TRUE;
  735.  
  736.                         (* Set the new row to the new process information *)
  737.                         SetProcessListInfo (procInfo, currCell.v, procList)
  738.                     END;
  739.  
  740.                 (* Go to the next cell element in List Mgr list *)
  741.                 currCell.v := SUCC (currCell.v)
  742.             END;
  743.  
  744.         (* Delete any extraneous cells *)
  745.         IF currCell.v < procList^^.dataBounds.bottom THEN
  746.             LDelRow (procList^^.dataBounds.bottom - currCell.v, currCell.v,
  747.                     procList);
  748.  
  749.         (* If added processes to the list and memory low, warn *)
  750.         IF addedProcess AND FailLowMemory (0) THEN
  751.             junkError := ShowCautionOKAlert (rMemErrMessages, kMemErrLowMemWarnMsg, junkItemHit)
  752.     END;
  753.  
  754.  
  755. {$S ProcessGuts}
  756. (*******************************************************************************
  757. * Public: DrawProcessListWindow
  758. *
  759. * Not much here to explain.
  760. *******************************************************************************)
  761.  
  762.     PROCEDURE DrawProcessListWindow (processListWindow: WindowPtr);
  763.  
  764.         VAR
  765.             procList: ListHandle; {Handle to List Mgr process list}
  766.  
  767.     BEGIN
  768.         SetPort (processListWindow);
  769.  
  770.         (* Get the List Manager’s copy of the process list *)
  771.         procList := ListHandle(GetWRefCon (processListWindow));
  772.  
  773.         (* Update the list *)
  774.         TextFont (applFont);
  775.         TextFace ([]);
  776.         TextSize (GetDefFontSize);
  777.         EraseRect (processListWindow^.portRect);
  778.         LUpdate (processListWindow^.visRgn, procList);
  779.     END;
  780.  
  781.  
  782. {$S ProcessGuts}
  783. (*******************************************************************************
  784. * Public: ClickProcessListWindow
  785. *
  786. * The List Manager is doing the lion’s share of the work.
  787. *******************************************************************************)
  788.  
  789.     PROCEDURE ClickProcessListWindow (processListWindow: WindowPtr;
  790.                                       clickEvent:        EventRecord);
  791.  
  792.         VAR
  793.             procList:    ListHandle; {Handle to List Mgr process list}
  794.             clickPos:    Point;      {Position of mouse click in window coords}
  795.             doubleClick: Boolean;    {TRUE if cell was double-clicked}
  796.  
  797.     BEGIN
  798.         SetPort (processListWindow);
  799.  
  800.         (* Get the List Manager’s copy of the process list *)
  801.         procList := ListHandle(GetWRefCon (processListWindow));
  802.  
  803.         (* Call the List Manager to handle the click *)
  804.         clickPos := clickEvent.where;
  805.         GlobalToLocal ((*◊*)clickPos);
  806.         doubleClick := LClick (clickPos, clickEvent.modifiers, procList);
  807.         IF doubleClick THEN
  808.             DoBringProcessToFront (processListWindow);
  809.     END;
  810.  
  811.  
  812. {$S ProcessGuts}
  813. (*******************************************************************************
  814. * Public: ActivateProcessListWindow
  815. *
  816. * The List Manager is called to activate/deactivate the process list window.
  817. *******************************************************************************)
  818.  
  819.     PROCEDURE ActivateProcessListWindow (processListWindow: WindowPtr;
  820.                                          becomingActive:    Boolean);
  821.  
  822.         VAR
  823.             procList: ListHandle; {Handle to List Mgr process list}
  824.  
  825.     BEGIN
  826.         SetPort (processListWindow);
  827.  
  828.         (* Get the List Manager’s copy of the process list *)
  829.         procList := ListHandle(GetWRefCon (processListWindow));
  830.  
  831.         (* Call the List Manager to activate or deactivate the list *)
  832.         LActivate (becomingActive, procList)
  833.     END;
  834.  
  835.  
  836. {$S ProcessGuts}
  837. (*******************************************************************************
  838. * Public: FixProcessListMenus
  839. *
  840. * The three launching items in the File menu are enabled as long as there’s
  841. * enough memory available.
  842. *
  843. * The List Manager routine, LGetSelect, is called to see if there are any
  844. * processes in the Process List window specified by the "processListWindow"
  845. * parameter that are selected.  If there are, then the three items in the
  846. * Process menu are enabled.  If there isn’t enough memory to safely work in,
  847. * then only the Bring Process to Front is enabled.
  848. *******************************************************************************)
  849.  
  850.     PROCEDURE FixProcessListMenus (processListWindow: WindowPtr);
  851.  
  852.         CONST
  853.             kFindNext = TRUE; {Pass to LGetSelect to find sequence of selections}
  854.  
  855.         VAR
  856.             aMenu:    MenuHandle; {Handle to any menu we’re checking on}
  857.             procList: ListHandle; {Handle to List Mgr process list}
  858.             aCell:    Cell;       {Cell of process list}
  859.  
  860.     BEGIN
  861.         (* Get the List Manager’s copy of the process list *)
  862.         procList := ListHandle(GetWRefCon (processListWindow));
  863.  
  864.         (* Enable the File menu launch items *)
  865.         aMenu := GetMenuHandle (mFile);
  866.         IF NOT FailLowMemory (0) THEN
  867.             BEGIN
  868.                 EnableItem (aMenu, iLaunchFore);
  869.                 EnableItem (aMenu, iLaunchBack);
  870.                 EnableItem (aMenu, iLaunchTo)
  871.             END;
  872.  
  873.         (* Undim the Process menu items *)
  874.         aMenu := GetMenuHandle (mProcess);
  875.         aCell.v := 0;
  876.         aCell.h := 0;
  877.         IF LGetSelect (kFindNext, (*◊*)aCell, procList) THEN
  878.             BEGIN
  879.                 (* There’s ≥ 1 sel’d process, enable Bring Process to Front *)
  880.                 EnableItem (aMenu, iBringFront);
  881.  
  882.                 (* Only enable other two items if enough memory to safely work *)
  883.                 IF NOT FailLowMemory (0) THEN
  884.                     BEGIN
  885.                         EnableItem (aMenu, iShowProcessInfo);
  886.                         EnableItem (aMenu, iTerminateProcess)
  887.                     END
  888.             END
  889.     END;
  890.  
  891.  
  892. {$S Main}
  893. (*******************************************************************************
  894. * Public: IsProcessInfoWindow
  895. *
  896. * I store a unique code in the windowKind field of every window I create so that
  897. * I can identify the kind of window it is later… like now!  I check to see if
  898. * the windowKind field of aWindow is kProcessInfoWindKind or not.  If it is, I
  899. * know it’s a process info window, and so IsProcessInfoWindow returns TRUE.
  900. *******************************************************************************)
  901.  
  902.     FUNCTION IsProcessInfoWindow (aWindow: WindowPtr): Boolean;
  903.  
  904.     BEGIN
  905.         IF aWindow <> NIL THEN
  906.             IsProcessInfoWindow := WindowPeek(aWindow)^.windowKind =
  907.                     kProcessInfoWindKind
  908.         ELSE
  909.             IsProcessInfoWindow := FALSE
  910.     END;
  911.  
  912.  
  913. {$S ProcessGuts}
  914. (*******************************************************************************
  915. * Private: GetNumberParts - Get the default number parts table
  916. *
  917. * To use the Script Manager’s number conversion routines, the number parts table
  918. * in the 'itl4' resource must be retrieved.  This routine gets the itl4 resource
  919. * and copies the number parts table into the "partsTable" parameter.
  920. *
  921. * If the retrieval was successful, then TRUE is returned.  If the itl4 resource
  922. * couldn’t be loaded for some reason, then FALSE is returned.
  923. *******************************************************************************)
  924.  
  925.     FUNCTION GetNumberParts (VAR partsTable: NumberParts): Boolean;
  926.  
  927.         VAR
  928.             intl4: Itl4Handle; {Handle to the itl4 resource}
  929.  
  930.     BEGIN
  931.         intl4 := Itl4Handle(GetIntlResource (4));
  932.         IF intl4 <> NIL THEN
  933.             BEGIN
  934.                 partsTable := NumberPartsPtr(ORD (intl4^) + intl4^^.
  935.                         defPartsOffset)^;
  936.                 GetNumberParts := TRUE
  937.             END
  938.         ELSE
  939.             GetNumberParts := FALSE
  940.     END;
  941.  
  942.  
  943. {$S ProcessGuts}
  944. (*******************************************************************************
  945. * Private: TextLineBox - Draw a line of text into a box.
  946. *
  947. * This routine is very similar to TextEdit’s TETextBox routine, and in fact it
  948. * takes the same parameters.  But TextLineBox draws a single line of text
  949. * specified by "textLine" and having the length specified by "length" into
  950. * the current GrafPort, ignoring carriage returns and word-wrap.  This means
  951. * that there’s less overhead than TETextBox.  But TETextBox itself is optimized for
  952. * single lines of text, so there is an ulterior motive for this routine.
  953. * TETextBox erases the entire box before drawing the text.  This results in a
  954. * slight flicker if TETextBox is called to draw over previous text.  TextLineBox
  955. * only erases the part of the box that isn’t covered with the text specified by
  956. * "textLine".  Also, the text is drawn in srcCopy mode.  If TextLineBox is
  957. * called to draw over existing text, the result should be a smooth transition
  958. * from one text to another, without flicker.
  959. *******************************************************************************)
  960.  
  961.     PROCEDURE TextLineBox (textLine: Ptr;
  962.                            length:   Integer;
  963.                            box:      Rect;
  964.                            just:     Integer);
  965.  
  966.         VAR
  967.             currPort:     GrafPtr;   {Pointer to the current GrafPort}
  968.             currTextMode: Integer;   {Current text mode}
  969.             currFont:     FontInfo;  {Current font information}
  970.             lineWidth:    Integer;   {Width of line of text in pixels}
  971.             spareSpace:   Integer;   {Width of box - width of text}
  972.             spareRect:    Rect;      {Rectangle of area not filled with text}
  973.             currClip:     RgnHandle; {Handle to the current clip region}
  974.  
  975.     BEGIN
  976.         (* Save the current clip region and set the clip region to "box" *)
  977.         currClip := NewRgn;
  978.         GetClip ((*<*)currClip);
  979.         ClipRect (box);
  980.  
  981.         (* Save the current text mode and set it to srcCopy *)
  982.         GetPort ((*<*)currPort);
  983.         currTextMode := currPort^.txMode;
  984.         TextMode (srcCopy);
  985.  
  986.         (* If default justification, set to real justification based on SysJust *)
  987.         IF just = teFlushDefault THEN
  988.             IF GetSysDirection = 0 THEN
  989.                 just := teFlushLeft
  990.             ELSE
  991.                 just := teFlushRight;
  992.  
  993.         (* Move pen to baseline on left side of box *)
  994.         GetFontInfo (currFont);
  995.         MoveTo (box.left, box.top + currFont.ascent);
  996.  
  997.         (* Find the width of the specified text *)
  998.         lineWidth := TextWidth (textLine, 0, length);
  999.  
  1000.         (* Adjust the pen for centered or right-aligned text *)
  1001.         IF just <> teFlushLeft THEN
  1002.             BEGIN
  1003.                 spareSpace := box.right - box.left - lineWidth;
  1004.                 IF just = teCenter THEN
  1005.                     spareSpace := spareSpace DIV 2;
  1006.                 Move (spareSpace, 0);
  1007.             END;
  1008.  
  1009.         (* Erase area at end(s) of text *)
  1010.         spareRect := box;
  1011.         IF just = teFlushLeft THEN
  1012.             spareRect.left := spareRect.left + lineWidth
  1013.         ELSE
  1014.             BEGIN
  1015.                 IF just = teCenter THEN
  1016.                     BEGIN
  1017.                         spareRect.left := spareRect.left + spareSpace + lineWidth;
  1018.                         EraseRect (spareRect)
  1019.                     END;
  1020.                 spareRect.left := box.left;
  1021.                 spareRect.right := spareRect.left + spareSpace;
  1022.             END;
  1023.         IF NOT EmptyRect (spareRect) THEN
  1024.             EraseRect (spareRect);
  1025.  
  1026.         (* Draw the line of text *)
  1027.         DrawText (textLine, 0, length);
  1028.  
  1029.         (* Restore the port to its normal state *)
  1030.         TextMode (currTextMode);
  1031.         SetClip (currClip);
  1032.         DisposeRgn (currClip)
  1033.     END;
  1034.  
  1035.  
  1036. {$S ProcessGuts}
  1037. (*******************************************************************************
  1038. * Private: FindProcessInfoWindow - Find a process info window for a process
  1039. *
  1040. * This routine searches the window list for a process info window that
  1041. * represents the process with the process serial number specified by
  1042. * "searchPSN".  Every process info window has a handle to the process serial
  1043. * number of the process it represents in the refCon field of the window.  The
  1044. * Process Manager routine, SameProcess, does the work of comparing the given
  1045. * process serial number against the process serial number in the refCon.
  1046. *
  1047. * If a window for the specified process is found, a pointer to that window is
  1048. * returned.  If there isn’t any window representing the given process, then NIL
  1049. * is returned.
  1050. *******************************************************************************)
  1051.  
  1052.     FUNCTION FindProcessInfoWindow (searchPSN: ProcessSerialNumber): WindowPtr;
  1053.  
  1054.         VAR
  1055.             testWindow: WindowPtr; {Pointer to window we’re testing}
  1056.             found:      Boolean;   {TRUE if matching process info window was found}
  1057.             psnHandle:  Handle;    {Handle to PSN of window’s process info window}
  1058.             error:      OSErr;
  1059.  
  1060.     BEGIN
  1061.         found := FALSE;
  1062.         testWindow := FrontWindow;
  1063.  
  1064.         (* Loop until the window is found or every window has been searched *)
  1065.         WHILE (testWindow <> NIL) AND (NOT found) DO
  1066.             BEGIN
  1067.                 IF IsProcessInfoWindow (testWindow) THEN
  1068.                     BEGIN
  1069.                         (* Get the PSN of the window from its refCon *)
  1070.                         psnHandle := Handle(GetWRefCon (testWindow));
  1071.  
  1072.                         (* Compare window’s PSN against searchPSN *)
  1073.                         HLock (psnHandle);
  1074.                         error := SameProcess (searchPSN, ProcessSerialNumberPtr(psnHandle^)^,
  1075.                                 (*<*)found);
  1076.                         HUnlock (psnHandle)
  1077.                     END;
  1078.  
  1079.                 (* Go to the next window in the window list *)
  1080.                 IF NOT found THEN
  1081.                     testWindow := WindowPtr(WindowPeek(testWindow)^.nextWindow)
  1082.             END;
  1083.  
  1084.         (* Return pointer to matching process info window, or NIL if no match *)
  1085.         FindProcessInfoWindow := testWindow
  1086.     END;
  1087.  
  1088.  
  1089. {$S ProcessGuts}
  1090. (*******************************************************************************
  1091. * Private: CloseProcessInfoWindow - Close a process info window
  1092. *
  1093. * The process info window specified by "processInfoWindow" is closed and all its
  1094. * associated memory is deallocated.
  1095. *******************************************************************************)
  1096.  
  1097.     PROCEDURE CloseProcessInfoWindow (processInfoWindow: WindowPtr);
  1098.  
  1099.     BEGIN
  1100.         DisposeHandle (Handle(GetWRefCon (processInfoWindow)));
  1101.         CloseWindow (processInfoWindow);
  1102.         DisposeDialogItems (processInfoWindow);
  1103.         DisposePtr (Ptr(processInfoWindow))
  1104.     END;
  1105.  
  1106.  
  1107. {$S ProcessGuts}
  1108. (*******************************************************************************
  1109. * Private: CreateProcessInfoWindow - Create a process info window
  1110. *
  1111. * This routine is called to create a new process info window and to display it
  1112. * on the screen.  A pointer to the window is returned.  If there wasn’t enough
  1113. * memory to open the new window, or if there was some other problem preventing
  1114. * the window from being completely created, then an alert indicating the problem
  1115. * is presented to the user and NIL is returned.
  1116. *
  1117. * I store the constant kProcessInfoWindKind into the windowKind field of the new
  1118. * window.  When the routine IsProcessInfoWindow is called, it uses this field to
  1119. * identify a window as a process info window.
  1120. *******************************************************************************)
  1121.  
  1122.     FUNCTION CreateProcessInfoWindow: WindowPtr;
  1123.  
  1124.         VAR
  1125.             aWindow: WindowPtr; {Pointer to the new window}
  1126.             error:   OSErr;
  1127.  
  1128.         PROCEDURE HandleError (messageClass: Integer;
  1129.                                messageIndex: Integer);
  1130.  
  1131.             VAR
  1132.                 junkError: OSErr;
  1133.                 junkItemHit: Integer; {Result of alert; ignored}
  1134.  
  1135.         BEGIN
  1136.             IF aWindow <> NIL THEN
  1137.                 CloseProcessInfoWindow (aWindow);
  1138.             junkError := ShowStopAlert (messageClass, messageIndex, junkItemHit);
  1139.             gError := noErr;
  1140.             CreateProcessInfoWindow := NIL;
  1141.             EXIT (CreateProcessInfoWindow)
  1142.         END;
  1143.  
  1144.     BEGIN
  1145.         aWindow := NIL;
  1146.  
  1147.         (* Create the new window *)
  1148.         aWindow := CreateDialog (rProcessInfoWindID);
  1149.         IF aWindow = NIL THEN
  1150.             IF gError = memFullErr THEN
  1151.                 HandleError (rMemErrMessages, kMemErrProcInfoOpenMsg)
  1152.             ELSE IF gError = resNotFound THEN
  1153.                 HandleError (rResErrMessages, kResErrAppDamageMsg)
  1154.             ELSE IF gError = dsSysErr THEN
  1155.                 HandleError (rMiscErrMessages, kMiscErrUnknownMsg);
  1156.  
  1157.         (* Set up the window *)
  1158.         SetPort (aWindow);
  1159.         WindowPeek(aWindow)^.windowKind := kProcessInfoWindKind;
  1160.  
  1161.         (* Install the dialog items *)
  1162.         error := InstallDialogItems (aWindow, rProcessInfoDitlID);
  1163.         IF error <> noErr THEN
  1164.             IF error = memFullErr THEN
  1165.                 HandleError (rMemErrMessages, kMemErrProcInfoOpenMsg)
  1166.             ELSE IF error = resNotFound THEN
  1167.                 HandleError (rResErrMessages, kResErrAppDamageMsg)
  1168.             ELSE IF error = dsSysErr THEN
  1169.                 HandleError (rMiscErrMessages, kMiscErrUnknownMsg);
  1170.  
  1171.         CreateProcessInfoWindow := aWindow
  1172.     END;
  1173.  
  1174.  
  1175. {$S ProcessGuts}
  1176. (*******************************************************************************
  1177. * Private: DrawGrayLine - Draw a gray line into a dialog item
  1178. *
  1179. * DrawGrayLine draws a line from the top-left corner of "grayLineRect" to its
  1180. * bottom-right corner.  On a non-Color QuickDraw Macintosh, this line is simply
  1181. * drawn using the 50% gray pattern.  On a Color QuickDraw Macintosh, a gray
  1182. * type-2 pattern is created with a gray color.  When this pattern is used to
  1183. * draw to the screen, it is drawn using the specified color if possible.  If
  1184. * there aren’t enough available colors, the color is dithered using the closest
  1185. * available colors.
  1186. *******************************************************************************)
  1187.  
  1188.     PROCEDURE DrawGrayLine (grayLineRect: Rect);
  1189.  
  1190.         VAR
  1191.             grayColor:   RGBColor;     {Color of gray line}
  1192.             grayPattern: PixPatHandle; {Handle to the gray pattern}
  1193.  
  1194.     BEGIN
  1195.         grayPattern := NIL;
  1196.         PenNormal;
  1197.  
  1198.         (* See if Color QuickDraw is on this machine or not *)
  1199.         IF NOT HasColourQuickDraw THEN
  1200.             (* Nope, just draw a 50% gray pattern *)
  1201.             PenPat (qd.gray)
  1202.         ELSE
  1203.             (* Yup, make a true gray pattern that can be dithered to the screen *)
  1204.             BEGIN
  1205.                 grayColor.red := $7FFF;
  1206.                 grayColor.green := $7FFF;
  1207.                 grayColor.blue := $7FFF;
  1208.                 grayPattern := NewPixPat;
  1209.                 MakeRGBPat (grayPattern, grayColor);
  1210.                 PenPixPat (grayPattern);
  1211.             END;
  1212.  
  1213.         (* Draw the line *)
  1214.         MoveTo (grayLineRect.left, grayLineRect.top);
  1215.         LineTo (grayLineRect.right, grayLineRect.bottom);
  1216.  
  1217.         (* Clean up *)
  1218.         IF grayPattern <> NIL THEN
  1219.             DisposePixPat (grayPattern);
  1220.         PenNormal
  1221.     END;
  1222.  
  1223. {$S ProcessGuts}
  1224. (*******************************************************************************
  1225. * Private: MyNumberString - Converts a number to an international friendly string
  1226. *
  1227. * Numbers are converted to strings using the ExtendedToString routine.  ExtendedToString
  1228. * requires a script-independent canonical number format so that the resulting
  1229. * string appears with the proper thousands separator regardless of the script
  1230. * in use.  I previously created a canonical number format that has the form
  1231. * ###,###,### in the U.S and saved it in a resource of type 'FMAT'.
  1232. *
  1233. * You can even use Michael Hecht's way cool 'FMAT' editor to play with this
  1234. * resource in ResEdit.  Get it from:
  1235.  
  1236.   <ftp://mirror.apple.com/mirrors/mac.archive.umich.edu/util/developer/
  1237.     fmateditor1.01.sit.hqx>
  1238. *******************************************************************************)
  1239.     PROCEDURE MyNumberString(number: LongInt; VAR numberStr: Str255);
  1240.         VAR
  1241.             partsTable:   NumberParts;      {Number parts table from itl4 resource}
  1242.             canonRsrc:    Handle;           {Hnd to canonical # format '###,###,###'}
  1243.             numberAsDouble:Double;            {for use with dtox80}
  1244.             numberAsExtended80:extended80;    {for use with ExtendedToString}
  1245.             success:       Boolean;          {TRUE if GetNumberParts call worked}
  1246.             status:        FormatStatus;    {Status of #->String conversion}
  1247.     BEGIN
  1248.         (* Starting here, convert number to a string *)
  1249.         numberAsDouble := number;
  1250.         {$ifc GENERATINGCFM}
  1251.             dtox80(numberAsDouble, numberAsExtended80);
  1252.         {$elsec}
  1253.             numberAsExtended80 := numberAsDouble;
  1254.         {$endc}
  1255.  
  1256.         (* Get number parts table from itl4 *)
  1257.         success := GetNumberParts ((*<*)partsTable);
  1258.         IF success THEN
  1259.             BEGIN
  1260.                 (* Get my canonical number format *)
  1261.                 canonRsrc := Get1Resource ('FMAT', 128);
  1262.                 IF canonRsrc <> NIL THEN
  1263.                     BEGIN
  1264.                         (* Convert free space to equivalent string *)
  1265.                         HLock (canonRsrc);
  1266.                         status := ExtendedToString (numberAsExtended80,
  1267.                                 NumFormatStringPtr(canonRsrc^)^, partsTable,
  1268.                                 (*<*)numberStr);
  1269.                         HUnlock (canonRsrc);
  1270.  
  1271.                     END;
  1272.             END;
  1273.     END;
  1274.  
  1275. {$S ProcessGuts}
  1276. (*******************************************************************************
  1277. * Private: SetUpProcessInfoItems - Set up process information static text items
  1278. *
  1279. * This routine sets up the text of the static text items in the process info
  1280. * window specified by "processInfoWindow" to reflect the process information
  1281. * passed in the "processInfo" parameter.  Only the process information that
  1282. * doesn’t change while a process is active is set in this routine.  Information
  1283. * that changes while a process is active is set and drawn in the
  1284. * IdleProcessInfoWindow routine.
  1285. *******************************************************************************)
  1286.  
  1287.     PROCEDURE SetUpProcessInfoItems (processInfoWindow: WindowPtr;
  1288.                                      processInfo:       ProcessInfoRec);
  1289.  
  1290.         VAR
  1291.             itemString:    Str255;       {"Application" or "Desk Accessory" string}
  1292.             blankString:   Integer;      {Dummy empty string}
  1293.             checkString:   StringPtr;    {Ptr either to check mark or blankString}
  1294.             checkStrHnd:   StringHandle; {Handle to check mark string}
  1295.  
  1296.     BEGIN
  1297.         (* Set process name *)
  1298.         SetStatTextItem (processInfoWindow, kProcessNameItem, @processInfo.
  1299.                 processName^ [1], ORD (processInfo.processName^ [0]));
  1300.  
  1301.         (* Set Application or Desk Accessory string *)
  1302.         IF BAND (processInfo.processMode, modeDeskAccessory) <> 0 THEN
  1303.             GetIndString ((*◊*)itemString, rAppOrDAStringID, kDAStringInd)
  1304.         ELSE
  1305.             GetIndString ((*◊*)itemString, rAppOrDAStringID, kAppStringInd);
  1306.         SetStatTextItem (processInfoWindow, kAppOrDAItem, @itemString [1],
  1307.                 ORD (itemString [0]));
  1308.  
  1309.         (* Set partition size item *)
  1310.         MyNumberString(processInfo.processSize DIV 1024, itemString);
  1311.  
  1312.         SetStatTextItem (processInfoWindow, kTotalSizeItem,
  1313.                 @itemString [1], ORD (itemString [0]));
  1314.  
  1315.         (* Set type and creator *)
  1316.         SetStatTextItem (processInfoWindow, kTypeItem, @processInfo.processType,
  1317.                 SIZEOF (LongInt));
  1318.         SetStatTextItem (processInfoWindow, kCreatorItem, @processInfo.
  1319.                 processSignature, SIZEOF (OSType));
  1320.  
  1321.         (* Initialize the checkmark and blank strings *)
  1322.         checkStrHnd := GetString (rCheckMarkID);
  1323.         IF checkStrHnd <> NIL THEN
  1324.             BlockMoveData (Ptr(checkStrHnd^), @itemString, ORD (checkStrHnd^^ [0]) + 1)
  1325.         ELSE
  1326.             itemString [0] := CHR (0);
  1327.         blankString := 0;
  1328.  
  1329.         (* Check the suspend/resume flag *)
  1330.         IF BAND (processInfo.processMode, modeNeedSuspendResume) <> 0 THEN
  1331.             checkString := @itemString
  1332.         ELSE
  1333.             checkString := @blankString;
  1334.         SetStatTextItem (processInfoWindow, kSusResChkItem, @checkString^ [1],
  1335.                 ORD (checkString^ [0]));
  1336.  
  1337.         (* Check the window activate flag *)
  1338.         IF BAND (processInfo.processMode, modeDoesActivateOnFGSwitch) <> 0 THEN
  1339.             checkString := @itemString
  1340.         ELSE
  1341.             checkString := @blankString;
  1342.         SetStatTextItem (processInfoWindow, kWindActChkItem, @checkString^ [1],
  1343.                 ORD (checkString^ [0]));
  1344.  
  1345.         (* Check the front clicks flag *)
  1346.         IF BAND (processInfo.processMode, modeGetFrontClicks) <> 0 THEN
  1347.             checkString := @itemString
  1348.         ELSE
  1349.             checkString := @blankString;
  1350.         SetStatTextItem (processInfoWindow, kGetClickChkItem, @checkString^ [1],
  1351.                 ORD (checkString^ [0]));
  1352.  
  1353.         (* Check the application-died event flag *)
  1354.         IF BAND (processInfo.processMode, modeGetAppDiedMsg) <> 0 THEN
  1355.             checkString := @itemString
  1356.         ELSE
  1357.             checkString := @blankString;
  1358.         SetStatTextItem (processInfoWindow, kAppDiedChkItem, @checkString^ [1],
  1359.                 ORD (checkString^ [0]));
  1360.  
  1361.         (* Check the stationery flag *)
  1362.         IF BAND (processInfo.processMode, modeStationeryAware) <> 0 THEN
  1363.             checkString := @itemString
  1364.         ELSE
  1365.             checkString := @blankString;
  1366.         SetStatTextItem (processInfoWindow, kStationeryChkItem, @checkString^ [1],
  1367.                 ORD (checkString^ [0]));
  1368.  
  1369.         (* Check the can background flag *)
  1370.         IF BAND (processInfo.processMode, modeCanBackground) <> 0 THEN
  1371.             checkString := @itemString
  1372.         ELSE
  1373.             checkString := @blankString;
  1374.         SetStatTextItem (processInfoWindow, kCanBackChkItem, @checkString^ [1],
  1375.                 ORD (checkString^ [0]));
  1376.  
  1377.         (* Check the background only flag *)
  1378.         IF BAND (processInfo.processMode, modeOnlyBackground) <> 0 THEN
  1379.             checkString := @itemString
  1380.         ELSE
  1381.             checkString := @blankString;
  1382.         SetStatTextItem (processInfoWindow, kOnlyBackChkItem, @checkString^ [1],
  1383.                 ORD (checkString^ [0]));
  1384.  
  1385.         (* Check the high-level event aware flag *)
  1386.         IF BAND (processInfo.processMode, modeHighLevelEventAware) <> 0 THEN
  1387.             checkString := @itemString
  1388.         ELSE
  1389.             checkString := @blankString;
  1390.         SetStatTextItem (processInfoWindow, kHighLevelChkItem, @checkString^ [1],
  1391.                 ORD (checkString^ [0]));
  1392.  
  1393.         (* Check the local and remote high-level event flag *)
  1394.         IF BAND (processInfo.processMode, modeLocalAndRemoteHLEvents) <> 0 THEN
  1395.             checkString := @itemString
  1396.         ELSE
  1397.             checkString := @blankString;
  1398.         SetStatTextItem (processInfoWindow, kRHighLevelChkItem, @checkString^ [1],
  1399.                 ORD (checkString^ [0]));
  1400.  
  1401.         (* Check the multiple launch flag *)
  1402.         IF BAND (processInfo.processMode, modeMultiLaunch) <> 0 THEN
  1403.             checkString := @itemString
  1404.         ELSE
  1405.             checkString := @blankString;
  1406.         SetStatTextItem (processInfoWindow, kMultiUserChkItem, @checkString^ [1],
  1407.                 ORD (checkString^ [0]));
  1408.  
  1409.         (* Check the 32-bit clean flag *)
  1410.         IF BAND (processInfo.processMode, mode32BitCompatible) <> 0 THEN
  1411.             checkString := @itemString
  1412.         ELSE
  1413.             checkString := @blankString;
  1414.         SetStatTextItem (processInfoWindow, k32BitCleanChkItem, @checkString^ [1],
  1415.                 ORD (checkString^ [0]));
  1416.  
  1417.         (* Check the use TextEdit services flag *)
  1418.         IF BAND (processInfo.processMode, modeUseTextEditServices) <> 0 THEN
  1419.             checkString := @itemString
  1420.         ELSE
  1421.             checkString := @blankString;
  1422.         SetStatTextItem (processInfoWindow, kUseTextEditServicesChkItem, @checkString^ [1],
  1423.                 ORD (checkString^ [0]));
  1424.  
  1425.         (* Check the Display Manager aware flag *)
  1426.         IF BAND (processInfo.processMode, modeDisplayManagerAware) <> 0 THEN
  1427.             checkString := @itemString
  1428.         ELSE
  1429.             checkString := @blankString;
  1430.         SetStatTextItem (processInfoWindow, kDisplayManagerAwareChkItem, @checkString^ [1],
  1431.                 ORD (checkString^ [0]));
  1432.  
  1433.     END;
  1434.  
  1435.  
  1436. {$S ProcessGuts}
  1437. (*******************************************************************************
  1438. * Public: IdleProcessInfoWindow
  1439. *
  1440. * The memory indicator and the free memory readout are updated with the current
  1441. * values.
  1442. *
  1443. * The free memory readout is a static text item in the DITL, but there’s no text
  1444. * for it.  Instead, I’m drawing into that item’s rectangle using TextLineBox.
  1445. * I set the item up as a static text item just so that I can specify the type
  1446. * characteristics of the free memory readout from the DITL resource rather than
  1447. * hard-coding them in this routine.
  1448. *******************************************************************************)
  1449.  
  1450.     PROCEDURE IdleProcessInfoWindow (processInfoWindow: WindowPtr);
  1451.  
  1452.         VAR
  1453.             processInfo:   ProcessInfoRec; {Process info for window’s process}
  1454.             psnHandle:     Handle;         {Handle to PSN of window’s process}
  1455.             freeAngle:     Integer;        {Angle between free and full memory}
  1456.             error:         OSErr;
  1457.             itemRect:      Rect;           {Rectangle of dialog item}
  1458.             itemType:     TypeInfoRec;     {Type information for free mem readout}
  1459.             freeSpaceStr:  Str255;           {Free space in process, as string}
  1460.             
  1461.     BEGIN
  1462.         SetPort (processInfoWindow);
  1463.         PenNormal;
  1464.  
  1465.         (* Get the PSN of the process associated with processInfoWindow *)
  1466.         psnHandle := Handle(GetWRefCon (processInfoWindow));
  1467.  
  1468.         (* Get information about an open process *)
  1469.         processInfo.processInfoLength := SIZEOF (ProcessInfoRec);
  1470.         processInfo.processName := NIL;
  1471.         processInfo.processAppSpec := NIL;
  1472.         HLock (psnHandle);
  1473.         error := GetProcessInformation (ProcessSerialNumberPtr(psnHandle^)^, (*◊*)processInfo);
  1474.         HUnlock (psnHandle);
  1475.  
  1476.         (* Check to see whether the process still exists *)
  1477.         IF error = procNotFound THEN
  1478.             (* Process terminated, so close this process info window *)
  1479.             CloseProcessInfoWindow (processInfoWindow)
  1480.         ELSE
  1481.             BEGIN
  1482.                 (* Starting here, convert amount of free space to a string *)
  1483.                 MyNumberString(processInfo.processFreeMem DIV 1024, freeSpaceStr);
  1484.  
  1485.                 (* Get the item rectangle of the free-space readout *)
  1486.                 GetDialogItemRect (processInfoWindow, kFreeSpaceItem, (*<*)itemRect);
  1487.  
  1488.                 (* Get the font characteristics of the stat text item *)
  1489.                 GetStatTextFontInfo (processInfoWindow, kFreeSpaceItem, (*<*)itemType);
  1490.  
  1491.                 (* Draw the free-space readout *)
  1492.                 TextFont (itemType.typeFace);
  1493.                 TextSize (itemType.typeSize);
  1494.                 TextFace (itemType.typeStyle);
  1495.                 TextLineBox (@freeSpaceStr [1], ORD (freeSpaceStr [0]),
  1496.                         itemRect, itemType.textJust);
  1497.  
  1498.                 (* Draw the memory indicator frame *)
  1499.                 GetDialogItemRect (processInfoWindow, kMemIndicatorItem,
  1500.                         (*<*)itemRect);
  1501.                 FrameOval (itemRect);
  1502.                 InsetRect ((*◊*)itemRect, 1, 1);
  1503.  
  1504.                 (* Calc angle in the memory indicator that the free memory begins *)
  1505.                 freeAngle := processInfo.processFreeMem * 360 DIV processInfo.
  1506.                         processSize;
  1507.  
  1508.                 (* Draw the memory indicator *)
  1509.                 IF NOT HasColourQuickDraw THEN
  1510.                     PenPat (qd.black)
  1511.                 ELSE
  1512.                     BEGIN
  1513.                         PmForeColor (kUsedColor);
  1514.                         PmBackColor (0)
  1515.                     END;
  1516.  
  1517.                 (* Draw the used memory part of the memory indicator *)
  1518.                 PaintArc (itemRect, 0, 360 - freeAngle);
  1519.  
  1520.                 (* Set the color of the free memory part of the indicator *)
  1521.                 IF NOT HasColourQuickDraw THEN
  1522.                     PenPat (qd.white)
  1523.                 ELSE
  1524.                     BEGIN
  1525.                         PmForeColor (kFreeColor);
  1526.                         PmBackColor (1)
  1527.                     END;
  1528.  
  1529.                 (* Draw the free memory part of the memory indicator *)
  1530.                 PaintArc (itemRect, 360 - freeAngle, freeAngle);
  1531.  
  1532.                 (* Reset the port characteristics back to normal *)
  1533.                 PenNormal;
  1534.                 IF HasColourQuickDraw THEN
  1535.                     BEGIN
  1536.                         PmForeColor (1);
  1537.                         PmBackColor (0)
  1538.                     END
  1539.             END
  1540.     END;
  1541.  
  1542.  
  1543. {$S ProcessGuts}
  1544. (*******************************************************************************
  1545. * Public: DrawProcessInfoWindow
  1546. *
  1547. * The Dialog Utility routine, DrawDialogItems, is called to draw all the
  1548. * standard dialog items in the processInfoWindow specified by processInfoWindow.
  1549. * Then, the cosmetic gray lines are drawn.  The memory readouts aren’t drawn
  1550. * because they’re drawn in IdleProcessInfoWindow.
  1551. *******************************************************************************)
  1552.  
  1553.     PROCEDURE DrawProcessInfoWindow (processInfoWindow: WindowPtr);
  1554.  
  1555.         VAR
  1556.             grayLineRect: Rect; {Rectangle of gray line item}
  1557.  
  1558.     BEGIN
  1559.         (* Draw the standard dialog items *)
  1560.         DrawDialogItems (processInfoWindow);
  1561.  
  1562.         (* Draw the two gray, cosmetic, separating lines *)
  1563.         GetDialogItemRect (processInfoWindow, kGrayLineItem0, (*<*)grayLineRect);
  1564.         DrawGrayLine (grayLineRect);
  1565.         GetDialogItemRect (processInfoWindow, kGrayLineItem1, (*<*)grayLineRect);
  1566.         DrawGrayLine (grayLineRect)
  1567.     END;
  1568.  
  1569.  
  1570. {$S ProcessGuts}
  1571. (*******************************************************************************
  1572. * Public: FixProcessInfoMenus
  1573. *
  1574. * If there’s enough memory to work with, the launch items in the File menu are
  1575. * enabled.
  1576. *******************************************************************************)
  1577.  
  1578.     PROCEDURE FixProcessInfoMenus (processInfoWindow: WindowPtr);
  1579.  
  1580.         VAR
  1581.             aMenu: MenuHandle; {Handle to any menu we’re checking on}
  1582.  
  1583.     BEGIN
  1584.         {$unused processInfoWindow}
  1585.         (* Undim the File menu items *)
  1586.         aMenu := GetMenuHandle (mFile);
  1587.         IF NOT FailLowMemory (0) THEN
  1588.             BEGIN
  1589.                 EnableItem (aMenu, iClose);
  1590.                 EnableItem (aMenu, iLaunchFore);
  1591.                 EnableItem (aMenu, iLaunchBack);
  1592.                 EnableItem (aMenu, iLaunchTo)
  1593.             END
  1594.     END;
  1595.  
  1596.  
  1597. {$S Main}
  1598. (*******************************************************************************
  1599. * Public: DoWindowClose
  1600. *
  1601. * As new kinds of windows are added to this application, this routine will have
  1602. * to be able to detect the new kind of window and dispatch to the routine that
  1603. * handles close requests for that kind of window.
  1604. *******************************************************************************)
  1605.  
  1606.     PROCEDURE DoWindowClose (eventWind: WindowPtr);
  1607.  
  1608.     BEGIN
  1609.         IF IsProcessInfoWindow (eventWind) THEN
  1610.             CloseProcessInfoWindow (eventWind);
  1611.     END;
  1612.  
  1613.  
  1614. {$S ProcessGuts}
  1615. (*******************************************************************************
  1616. * Public: IdleAllProcessWindows
  1617. *
  1618. * The process list window and process info windows each have their own idle
  1619. * routine defined in this source file, so the type of window is checked and the
  1620. * appropriate idle routine is called for that window.
  1621. *******************************************************************************)
  1622.  
  1623.     PROCEDURE IdleAllProcessWindows;
  1624.  
  1625.         VAR
  1626.             processWindow: WindowPtr; {Pointer to each process window being idled}
  1627.  
  1628.     BEGIN
  1629.         processWindow := FrontWindow;
  1630.  
  1631.         (* Loop through all windows in the window list *)
  1632.         WHILE processWindow <> NIL DO
  1633.             BEGIN
  1634.                 (* Call the appropriate idle routine if it’s a process window *)
  1635.                 IF IsProcessListWindow (processWindow) THEN
  1636.                     IdleProcessListWindow (processWindow)
  1637.                 ELSE IF IsProcessInfoWindow (processWindow) THEN
  1638.                     IdleProcessInfoWindow (processWindow);
  1639.  
  1640.                 (* Go to the next window in the window list *)
  1641.                 processWindow := WindowPtr(WindowPeek(processWindow)^.nextWindow)
  1642.             END
  1643.     END;
  1644.  
  1645.  
  1646. {$S ProcessGuts}
  1647. (*******************************************************************************
  1648. * Private: AppDAFilterProc - File filter procedure for apps and files with DAs
  1649. *
  1650. *     This is a Standard File file filter procedure that allows applications and
  1651. * any files with desk accessories in them to show up in the Standard File file
  1652. * list.
  1653. *
  1654. *     Checking to see whether a file is an application is easy enough.  Just
  1655. * check to see whether its type is APPL.  If it is, then it’s an application.
  1656. * Checking on desk accessories is trickier.  Desk accessories can be contained
  1657. * in any type of file.  So if a file isn’t doesn’t have the APPL type, I open
  1658. * the resource fork of the file using HOpenResFile and an access mode of
  1659. * fdRdPerm.  This allows me to open and close the resource file without worrying
  1660. * about that resource file being open by someone else because HOpenResFile with
  1661. * an access mode of fdRdPerm returns a unique access path to this routine.  When
  1662. * the file is open, I check for DRVR resources.  DRVR resources can be either
  1663. * desk accessories or device drivers.  I only want to show files containing desk
  1664. * accessories, so I check on the first character of the DRVR resource’s name.
  1665. * If it’s a null character, then the DRVR is a desk accessory.  If it’s any
  1666. * other character, then it’s a device driver and I ignore it.
  1667. *******************************************************************************)
  1668.  
  1669.     FUNCTION AppDAFilterProc (fileInfo: CInfoPBPtr): Boolean;
  1670.  
  1671.         CONST
  1672.             kShowIt = FALSE; {FALSE means I do not filter out...}
  1673.  
  1674.         VAR
  1675.             resRef:     Integer; {File ref num of file being tested}
  1676.             currResRef: Integer; {File ref number of current file}
  1677.             numDrvrs:   Integer; {Number of DRVR resources in file being tested}
  1678.             index:      Integer; {Index into resources of file being tested}
  1679.             drvrRsrc:   Handle;  {Handle to DRVR resource; always NIL master ptr}
  1680.             resID:      Integer; {Resource ID of DRVR resource; ignored}
  1681.             junkResType:ResType; {Resource type of DRVR resource; ignored}
  1682.             resName:    Str255;  {Resource name of DRVR resource}
  1683.  
  1684.     BEGIN
  1685.         IF fileInfo^.ioFlFndrInfo.fdType ='APPL' THEN
  1686.             AppDAFilterProc := kShowIt
  1687.         ELSE
  1688.             BEGIN
  1689.                 (* Assume we don’t show the file *)
  1690.                 AppDAFilterProc := NOT kShowIt;
  1691.  
  1692.                 (* Want to check rsrcs, not load ’em, including preload resources *)
  1693.                 SetResLoad (FALSE);
  1694.  
  1695.                 (* Save current res file refnum, open the specified rsrc file *)
  1696.                 currResRef := CurResFile;
  1697.                 resRef := HOpenResFile (fileInfo^.ioVRefNum,
  1698.                         LMGetCurDirStore, fileInfo^.ioNamePtr^, fsRdPerm);
  1699.  
  1700.                 (* If couldn’t open resource file, HOpenResFile returns -1 *)
  1701.                 IF (resRef <> -1) THEN
  1702.                     BEGIN
  1703.                         UseResFile (resRef);
  1704.  
  1705.                         (* Count number of DRVR resources in the file *)
  1706.                         numDrvrs := Count1Resources ('DRVR');
  1707.                         IF numDrvrs > 0 THEN
  1708.                             BEGIN
  1709.                                 (* For each DRVR, see if it’s a DA *)
  1710.                                 FOR index := 1 TO numDrvrs DO
  1711.                                     BEGIN
  1712.                                         drvrRsrc := Get1IndResource ('DRVR', index);
  1713.                                         GetResInfo (drvrRsrc, (*<*)resID, (*<*)junkResType,
  1714.                                                 (*<*)resName);
  1715.         
  1716.                                         (* If first char of name is null, it’s a DA *)
  1717.                                         IF resName [1] = CHR (0) THEN
  1718.                                             AppDAFilterProc := kShowIt
  1719.                                     END
  1720.                             END;
  1721.                         CloseResFile (resRef)
  1722.                     END;
  1723.         
  1724.                 (* Restore everything back to what it was *)
  1725.                 UseResFile (currResRef);
  1726.                 SetResLoad (TRUE)
  1727.             END
  1728.     END;
  1729.  
  1730.  
  1731. {$S ProcessGuts}
  1732. (*******************************************************************************
  1733. * Private: LaunchCycle - Attempt to launch a process
  1734. *
  1735. * This routine calls the LaunchProcess routine that’s in the UProcessUtils unit.
  1736. * The launchFile parameter specifies the file to launch.  The docList parameter
  1737. * specifies the list of documents to pass to the launched application for it to
  1738. * open or print.  The launchOptions parameter specifies the initial set of
  1739. * launch options to use when launching.  The the section titled “Specifying
  1740. * Launch Options” in the Process Manager chapter of Inside Macintosh VI for the
  1741. * a list and description of the launch options that you can pass in this
  1742. * parameter.
  1743. *
  1744. * If the Process Manager denies the launch, then LaunchProcess returns the
  1745. * resulting error code in the LaunchError flag.  If this happens and if the
  1746. * error happened to be that the machine is in 32-bit addressing mode and the
  1747. * application’s SIZE resource doesn’t have the 32-bit clean flag on, or if there
  1748. * isn’t enough memory to launch the application or desk accessory, then an alert
  1749. * is presented to the user asking if he or she wants to continue anyway.  If the
  1750. * user specifies that he or she does, then launch options are added to the ones
  1751. * passed in the launchOptions parameter which allow 32-bit unclean applications
  1752. * to launch or to allow the launch into available memory, and then LaunchProcess
  1753. * is called again.  This is repeated either until the application or desk
  1754. * accessory is successfully launched, the user chose not to launch it, or until
  1755. * an unrecoverable error occurs.
  1756. *******************************************************************************)
  1757.  
  1758.     PROCEDURE LaunchCycle (launchFile:    FSSpec;
  1759.                            docList:       DocListHnd;
  1760.                            launchOptions: Integer);
  1761.  
  1762.         VAR
  1763.             processNum:    ProcessSerialNumber; {Serial number of launched process}
  1764.             attemptLaunch: Boolean;             {TRUE if continuing launch attempt}
  1765.             result:        Integer;             {Result of caution alert}
  1766.             launchError:   OSErr;               {Launch error code}
  1767.             error:         OSErr;
  1768.             junkError:       OSErr;
  1769.  
  1770.     BEGIN
  1771.         (* Repeat until successful launch or cancelled launch *)
  1772.         REPEAT
  1773.             (* Attempt to launch the process *)
  1774.             error := LaunchProcess (launchFile, NIL, docList, launchOptions,
  1775.                     (*<*)processNum, (*<*)launchError);
  1776.  
  1777.             (* Check for launching errors *)
  1778.             IF launchError <> noErr THEN
  1779.                 BEGIN
  1780.                     (* There was a launching error, present to user *)
  1781.                     IF launchError = appModeErr THEN
  1782.                         BEGIN
  1783.                             (* Ask user if it’s OK to launch 32-bit unclean app *)
  1784.                             IF (ShowCautionOKCancelAlert (rMiscWrnMessages,
  1785.                                     kMiscWrnUncleanMsg, result) = noErr) & (result = ok) THEN
  1786.                                 BEGIN
  1787.                                     (* Try launch again, allowing 32-bit unclean app *)
  1788.                                     launchOptions := BOR (launchOptions,
  1789.                                             launchAllow24Bit);
  1790.                                     attemptLaunch := TRUE
  1791.                                 END
  1792.                             ELSE
  1793.                                 attemptLaunch := FALSE
  1794.                         END
  1795.                     ELSE IF launchError = memFullErr THEN
  1796.                         BEGIN
  1797.                             (* Ask user if it’s OK to launch w/ < requested memory *)
  1798.                             IF (ShowCautionOKCancelAlert (rMiscWrnMessages,
  1799.                                     kMiscWrnLaunchMemMsg, result) = noErr) & (result = ok) THEN
  1800.                                 BEGIN
  1801.                                     (* Try launch again, with less than requested mem *)
  1802.                                     launchOptions := BOR (launchOptions,
  1803.                                             launchUseMinimum);
  1804.                                     attemptLaunch := TRUE
  1805.                                 END
  1806.                             ELSE
  1807.                                 attemptLaunch := FALSE
  1808.                         END
  1809.                     ELSE
  1810.                         BEGIN
  1811.                             (* Some error we don’t handle happened *)
  1812.                             junkError := ShowStopAlert (rMiscErrMessages,
  1813.                                     kMiscErrUnknownMsg, result);
  1814.                             attemptLaunch := FALSE
  1815.                         END
  1816.                 END
  1817.             ELSE IF error <> noErr THEN
  1818.                 BEGIN
  1819.                     junkError := ShowStopAlert (rMiscErrMessages,
  1820.                             kMiscErrUnknownMsg, result);
  1821.                     attemptLaunch := FALSE
  1822.                 END
  1823.             ELSE
  1824.                 attemptLaunch := FALSE
  1825.         UNTIL NOT attemptLaunch;
  1826.     END;
  1827.  
  1828.  
  1829. {$S ProcessGuts}
  1830. (*******************************************************************************
  1831. * Public: DoLaunchInFront
  1832. *
  1833. * If the user is launching with documents, then only applications are presented
  1834. * to the user in the standard-file dialog.  If the user only wants to launch
  1835. * without any documents, then both applications and files containing desk
  1836. * accessories are presented to the user.
  1837. *******************************************************************************)
  1838.  
  1839.     PROCEDURE DoLaunchInFront;
  1840.  
  1841.         VAR
  1842.             reply:       StandardFileReply; {Reply from SFGetFile}
  1843.             typeList:    SFTypeList;        {List of file types for SF}
  1844.             launchSpec:  FSSpec;            {Location of selected app/DA}
  1845.             docList:     DocListHnd;        {Handle to the document list}
  1846.             gettingDocs: Boolean;           {True if user still getting docs}
  1847.             launchMode:  LaunchModeCode;    {Current launch mode}
  1848.             error:       OSErr;
  1849.  
  1850.     BEGIN
  1851.         (* Get the user’s choice for a file to launch *)
  1852.         launchMode := GetLaunchMode;
  1853.         IF launchMode = kJustLaunch THEN
  1854.             (* Just launching, so launch applications and DAs *)
  1855.             StandardGetFile (gAppDAFilterUPP, -1, @typeList, (*<*)reply)
  1856.         ELSE IF (launchMode = kOpenLaunch) OR (launchMode = kPrintLaunch) THEN
  1857.             BEGIN
  1858.                 (* Launching with documents, so launch applications only *)
  1859.                 typeList [0] := 'APPL';
  1860.                 StandardGetFile (NIL, 1, @typeList, (*<*)reply)
  1861.             END;
  1862.  
  1863.         IF reply.sfGood THEN
  1864.             BEGIN
  1865.                 launchSpec := reply.sfFile;
  1866.  
  1867.                 (* Check to see if documents should be opened/printed as well *)
  1868.                 IF (launchMode = kOpenLaunch) OR (launchMode = kPrintLaunch) THEN
  1869.                     BEGIN
  1870.                         (* Create an empty list of documents *)
  1871.                         docList := CreateDocList (launchMode);
  1872.  
  1873.                         (* Keep getting documents until user chooses Cancel *)
  1874.                         gettingDocs := TRUE;
  1875.                         WHILE gettingDocs DO
  1876.                             BEGIN
  1877.                                 StandardGetFile (NIL, -1, @typeList, (*<*)reply);
  1878.                                 IF reply.sfGood THEN
  1879.                                     error := AddToDocList (reply.sfFile, (*◊*)docList)
  1880.                                 ELSE
  1881.                                     gettingDocs := FALSE
  1882.                             END
  1883.                     END
  1884.                 ELSE
  1885.                     docList := NIL;
  1886.  
  1887.                 (* Attempt to launch the application *)
  1888.                 LaunchCycle (launchSpec, docList, launchContinue);
  1889.  
  1890.                 (* Dispose of the document list, if there was one *)
  1891.                 IF docList <> NIL THEN
  1892.                     DisposeDocList (docList)
  1893.             END
  1894.     END;
  1895.  
  1896.  
  1897. {$S ProcessGuts}
  1898. (*******************************************************************************
  1899. * Public: DoLaunchInBack
  1900. *
  1901. *******************************************************************************)
  1902.  
  1903.     PROCEDURE DoLaunchInBack;
  1904.  
  1905.         VAR
  1906.             reply:       StandardFileReply; {Reply from SFGetFile}
  1907.             typeList:    SFTypeList;        {List of file types to diplay in SF}
  1908.             launchSpec:  FSSpec;            {Location of selected application}
  1909.             docList:     DocListHnd;        {Handle to the document list}
  1910.             gettingDocs: Boolean;           {True if user still getting docs}
  1911.             launchMode:  LaunchModeCode;    {Current launch mode}
  1912.             error:       OSErr;
  1913.  
  1914.     BEGIN
  1915.         (* Get the user’s choice for an application to launch *)
  1916.         typeList [0] := 'APPL';
  1917.         StandardGetFile (NIL, 1, @typeList, (*<*)reply);
  1918.  
  1919.         IF reply.sfGood THEN
  1920.             BEGIN
  1921.                 (* Convert working directory and file name to FSSpec *)
  1922.                 launchSpec := reply.sfFile;
  1923.  
  1924.                 launchMode := GetLaunchMode;
  1925.                 IF (launchMode = kOpenLaunch) OR (launchMode = kPrintLaunch) THEN
  1926.                     BEGIN
  1927.                         (* Create an empty list of documents *)
  1928.                         docList := CreateDocList (launchMode);
  1929.  
  1930.                         (* Keep getting documents until user chooses Cancel *)
  1931.                         gettingDocs := TRUE;
  1932.                         WHILE gettingDocs DO
  1933.                             BEGIN
  1934.                                 StandardGetFile (NIL, -1, @typeList, (*<*)reply);
  1935.                                 IF reply.sfGood THEN
  1936.                                     error := AddToDocList (reply.sfFile, (*◊*)docList)
  1937.                                 ELSE
  1938.                                     gettingDocs := FALSE
  1939.                             END
  1940.                     END
  1941.                 ELSE
  1942.                     docList := NIL;
  1943.  
  1944.                 (* Attempt to launch the application *)
  1945.                 LaunchCycle (launchSpec, docList, launchContinue +
  1946.                         launchDontSwitch);
  1947.  
  1948.                 (* Dispose of the document list, if there was one *)
  1949.                 IF docList <> NIL THEN
  1950.                     DisposeDocList (docList)
  1951.             END
  1952.     END;
  1953.  
  1954.  
  1955. {$S ProcessGuts}
  1956. (*******************************************************************************
  1957. * Public: DoLaunchTo
  1958. *
  1959. *******************************************************************************)
  1960.  
  1961.     PROCEDURE DoLaunchTo;
  1962.  
  1963.         VAR
  1964.             reply:       StandardFileReply; {Reply from SFGetFile}
  1965.             typeList:    SFTypeList;        {List of file types to diplay in SF}
  1966.             launchSpec:  FSSpec;            {Location of selected file}
  1967.             docList:     DocListHnd;        {Handle to the document list}
  1968.             gettingDocs: Boolean;           {True if user still getting docs}
  1969.             launchMode:  LaunchModeCode;    {Current launch mode}
  1970.             error:       OSErr;
  1971.  
  1972.     BEGIN
  1973.         (* Get the user’s choice for a file to launch *)
  1974.         launchMode := GetLaunchMode;
  1975.         IF launchMode = kJustLaunch THEN
  1976.             (* Just launching, so launch applications and DAs *)
  1977.             StandardGetFile (gAppDAFilterUPP, -1, @typeList, (*<*)reply)
  1978.         ELSE IF (launchMode = kOpenLaunch) OR (launchMode = kPrintLaunch) THEN
  1979.             BEGIN
  1980.                 (* Launching with documents, so launch applications only *)
  1981.                 typeList [0] := 'APPL';
  1982.                 StandardGetFile (NIL, 1, @typeList, (*<*)reply)
  1983.             END;
  1984.  
  1985.         IF reply.sfGood THEN
  1986.             BEGIN
  1987.                 (* Convert working directory and file name to FSSpec *)
  1988.                 launchSpec := reply.sfFile;
  1989.  
  1990.                 IF (launchMode = kOpenLaunch) OR (launchMode = kPrintLaunch) THEN
  1991.                     BEGIN
  1992.                         (* Create an empty list of documents *)
  1993.                         docList := CreateDocList (launchMode);
  1994.  
  1995.                         (* Keep getting documents until user chooses Cancel *)
  1996.                         gettingDocs := TRUE;
  1997.                         WHILE gettingDocs DO
  1998.                             BEGIN
  1999.                                 StandardGetFile (NIL, -1, @typeList, (*<*)reply);
  2000.                                 IF reply.sfGood THEN
  2001.                                     error := AddToDocList (reply.sfFile, (*◊*)docList)
  2002.                                 ELSE
  2003.                                     gettingDocs := FALSE
  2004.                             END
  2005.                     END
  2006.                 ELSE
  2007.                     docList := NIL;
  2008.  
  2009.                 (* Attempt to launch the application or DA *)
  2010.                 LaunchCycle (launchSpec, docList, launchAllow24Bit);
  2011.  
  2012.                 (* Dispose of the document list, if there was one *)
  2013.                 IF docList <> NIL THEN
  2014.                     DisposeDocList (docList)
  2015.             END
  2016.     END;
  2017.  
  2018.  
  2019. {$S ProcessGuts}
  2020. (*******************************************************************************
  2021. * Public: DoLaunchMode
  2022. *
  2023. * SetLaunchMode does most of the work, and there isn’t much to do.
  2024. *******************************************************************************)
  2025.  
  2026.     PROCEDURE DoLaunchMode (modeItem: Integer);
  2027.  
  2028.     BEGIN
  2029.         CASE modeItem OF
  2030.             iJustLaunch:
  2031.                 SetLaunchMode (kJustLaunch);
  2032.             iOpenLaunch:
  2033.                 SetLaunchMode (kOpenLaunch);
  2034.             iPrintLaunch:
  2035.                 SetLaunchMode (kPrintLaunch)
  2036.         END
  2037.     END;
  2038.  
  2039.  
  2040. {$S ProcessGuts}
  2041. (*******************************************************************************
  2042. * Public: DoBringProcessToFront
  2043. *
  2044. * The List Manager is called to get each selection in the process list window.
  2045. * SetFrontProcess is called with the process serial number of each selected
  2046. * process.  They aren’t immediately brought to the front when SetFrontProcess is
  2047. * called.  Instead, they are scheduled to come to the front in the same order as
  2048. * they were presented to SetFrontProcess.  Once ProcDoggie reenters the main
  2049. * event loop, the Process Manager brings each scheduled process to the front in
  2050. * turn.
  2051. *
  2052. * At the moment, I can’t get ProcDoggie itself to be scheduled.  I assume it’s
  2053. * because SetFrontProcess checks to see if process serial number you passed it
  2054. * is the same as the process serial number of the current process.  If it is, it
  2055. * doesn’t bother to schedule the process.  I’m not quite sure how to work around
  2056. * that.
  2057. *
  2058. * I checked with the Process Manager source and the above explanation is correct.
  2059. * -- Quinn 10 Mar 1997
  2060. *******************************************************************************)
  2061.  
  2062.     PROCEDURE DoBringProcessToFront (processListWindow: WindowPtr);
  2063.  
  2064.         CONST
  2065.             kFindNext = TRUE; {Pass to LGetSelect to find sequence of selections}
  2066.  
  2067.         VAR
  2068.             procList:     ListHandle;         {Handle to List Mgr process list}
  2069.             currCell:     Point;              {Cell that has selection}
  2070.             listInfo:     ProcessListInfoRec; {Process info from List Mgr list}
  2071.             gotSelection: Boolean;            {T if got sel’d cell, F if no more}
  2072.             listInfoLen:  Integer;            {Length of list info in bytes}
  2073.             error:        OSErr;
  2074.  
  2075.     BEGIN
  2076.         (* Get the List Manager’s copy of the process list *)
  2077.         procList := ListHandle(GetWRefCon (processListWindow));
  2078.  
  2079.         (* Keep looping until all selected processes have been brought to front *)
  2080.         currCell.v := 0;
  2081.         currCell.h := 0;
  2082.         gotSelection := TRUE;
  2083.         WHILE gotSelection DO
  2084.             BEGIN
  2085.                 gotSelection := LGetSelect (kFindNext, (*◊*)currCell, procList);
  2086.                 IF gotSelection THEN
  2087.                     BEGIN
  2088.                         listInfoLen := SIZEOF (ProcessListInfoRec);
  2089.                         LGetCell (Ptr(@listInfo), (*◊*)listInfoLen, currCell,
  2090.                                 procList);
  2091.                         error := SetFrontProcess (listInfo.serialNumber);
  2092.                         currCell.v := currCell.v + 1
  2093.                     END
  2094.             END
  2095.     END;
  2096.  
  2097.  
  2098. {$S ProcessGuts}
  2099. (*******************************************************************************
  2100. * Public: DoGetProcessInfo
  2101. *
  2102. * This routine loops until Process Information windows for all selected
  2103. * processes in the Process List window are displayed.  Information for each
  2104. * process in the process list is retrieved from the list itself.  Then, that
  2105. * process is compared against all existing Process Information windows.  If a
  2106. * Process Information window already exists for that process, then that window
  2107. * is simply activated and DoGetProcessInfo exits.  Otherwise, the Process
  2108. * Manager is called to retrieve information for that process.  A new Process
  2109. * Information window is created, and its contents are set to the information
  2110. * retrieved for the process.
  2111. *******************************************************************************)
  2112.  
  2113.     PROCEDURE DoGetProcessInfo (processListWindow: WindowPtr);
  2114.  
  2115.         CONST
  2116.             kFindNext = TRUE; {Pass to LGetSelect to find sequence of selections}
  2117.  
  2118.         VAR
  2119.             procList:          ListHandle;         {Handle to List Mgr proc list}
  2120.             currCell:          Point;              {Cell that has selection}
  2121.             listInfo:          ProcessListInfoRec; {Proc info from List Mgr list}
  2122.             gotSelection:      Boolean;            {T if got sel’d cell, F if none}
  2123.             listInfoLen:       Integer;            {Length of list info in bytes}
  2124.             processInfo:       ProcessInfoRec;     {Info about selected processes}
  2125.             procName:          Str255;             {Name of selected processes}
  2126.             procSpec:          FSSpec;             {File spec of sel’d processes}
  2127.             processInfoWindow: WindowPtr;          {Ptr to new process info window}
  2128.             psnHandle:         Handle;             {Handle to PSN of chosen proc}
  2129.             existingWindow:    WindowPtr;          {Proc info wind if already open}
  2130.             error:             OSErr;
  2131.  
  2132.         PROCEDURE HandleError (messageClass: Integer;
  2133.                                messageIndex: Integer);
  2134.  
  2135.             VAR
  2136.                 junkError: OSErr;
  2137.                 result: Integer; {Result of alert; ignored}
  2138.  
  2139.         BEGIN
  2140.             IF processInfoWindow <> NIL THEN
  2141.                 CloseProcessInfoWindow (processInfoWindow);
  2142.             junkError := ShowStopAlert (messageClass, messageIndex, result);
  2143.             gError := noErr;
  2144.             EXIT (DoGetProcessInfo)
  2145.         END;
  2146.  
  2147.     BEGIN
  2148.         (* Get the List Manager’s copy of the process list *)
  2149.         procList := ListHandle(GetWRefCon (processListWindow));
  2150.  
  2151.         (* Keep looping until all selected processes have been brought to front *)
  2152.         currCell.v := 0;
  2153.         currCell.h := 0;
  2154.         gotSelection := TRUE;
  2155.         WHILE gotSelection DO
  2156.             BEGIN
  2157.                 gotSelection := LGetSelect (kFindNext, (*◊*)currCell, procList);
  2158.                 IF gotSelection THEN
  2159.                     BEGIN
  2160.                         listInfoLen := SIZEOF (ProcessListInfoRec);
  2161.                         LGetCell (Ptr(@listInfo), (*◊*)listInfoLen, currCell,
  2162.                                 procList);
  2163.  
  2164.                         (* See if proc info wind already exists for selected proc *)
  2165.                         existingWindow := FindProcessInfoWindow (listInfo.
  2166.                                 serialNumber);
  2167.                         IF existingWindow <> NIL THEN
  2168.                             SelectWindow (existingWindow)
  2169.                         ELSE
  2170.                             BEGIN
  2171.                                 (* Get information about an open process *)
  2172.                                 processInfo.processInfoLength :=
  2173.                                         SIZEOF (ProcessInfoRec);
  2174.                                 processInfo.processName := @procName;
  2175.                                 processInfo.processAppSpec := @procSpec;
  2176.                                 error := GetProcessInformation (listInfo.serialNumber,
  2177.                                         (*◊*)processInfo);
  2178.                                 IF error <> noErr THEN
  2179.                                     HandleError (rMiscErrMessages, kMiscErrUnknownMsg);
  2180.  
  2181.                                 (* Create the process information window *)
  2182.                                 processInfoWindow := CreateProcessInfoWindow;
  2183.                                 IF processInfoWindow <> NIL THEN
  2184.                                     BEGIN
  2185.                                         (* Put handle to PSN into refCon *)
  2186.                                         psnHandle := NewHandleMargin (SIZEOF
  2187.                                                 (ProcessSerialNumber), kAllocApp,
  2188.                                                 NOT kAllocClr);
  2189.                                         IF psnHandle = NIL THEN
  2190.                                             HandleError (rMemErrMessages,
  2191.                                                     kMemErrProcInfoOpenMsg);
  2192.                                         BlockMoveData (Ptr(@processInfo.processNumber),
  2193.                                                 psnHandle^, SIZEOF (ProcessSerialNumber));
  2194.                                         SetWRefCon (processInfoWindow,
  2195.                                                 LongInt(psnHandle));
  2196.  
  2197.                                         (* Update dlog items to reflect proc info *)
  2198.                                         SetUpProcessInfoItems (processInfoWindow,
  2199.                                                 processInfo);
  2200.                                     END
  2201.                                 ELSE
  2202.                                     gotSelection := FALSE
  2203.                             END;
  2204.  
  2205.                         (* Go to the next cell *)
  2206.                         currCell.v := currCell.v + 1
  2207.                     END
  2208.             END
  2209.     END;
  2210.  
  2211.  
  2212. {$S ProcessGuts}
  2213. (*******************************************************************************
  2214. * Public: DoTerminateProcess
  2215. *
  2216. * The List Manager is used to get all of the selected processes in
  2217. * processListWindow.  The process serial number of each of these processes is
  2218. * extracted and is then used when calling TerminateProcess.
  2219. *******************************************************************************)
  2220.  
  2221.     PROCEDURE DoTerminateProcess (processListWindow: WindowPtr);
  2222.  
  2223.         CONST
  2224.             kFindNext = TRUE; {Pass to LGetSelect to find sequence of selections}
  2225.  
  2226.         VAR
  2227.             procList:     ListHandle;         {Handle to List Mgr process list}
  2228.             currCell:     Point;              {Cell that has selection}
  2229.             listInfo:     ProcessListInfoRec; {Process info from List Mgr list}
  2230.             listInfoLen:  Integer;            {Length of list info in bytes}
  2231.             gotSelection: Boolean;            {T if got sel’d cell, F if none}
  2232.             error:        OSErr;
  2233.  
  2234.         PROCEDURE HandleError (messageClass: Integer;
  2235.                                messageIndex: Integer);
  2236.  
  2237.             VAR
  2238.                 junkError: OSErr;
  2239.                 result: Integer; {Result of alert; ignored}
  2240.  
  2241.         BEGIN
  2242.             junkError := ShowStopAlert (messageClass, messageIndex, result);
  2243.             gError := noErr;
  2244.             EXIT (DoTerminateProcess)
  2245.         END;
  2246.  
  2247.     BEGIN
  2248.         (* Get the List Manager’s copy of the process list *)
  2249.         procList := ListHandle(GetWRefCon (processListWindow));
  2250.  
  2251.         (* Keep looping until all selected processes have been terminated *)
  2252.         currCell.v := 0;
  2253.         currCell.h := 0;
  2254.         gotSelection := TRUE;
  2255.         WHILE gotSelection DO
  2256.             BEGIN
  2257.                 gotSelection := LGetSelect (kFindNext, (*◊*)currCell, procList);
  2258.                 IF gotSelection THEN
  2259.                     BEGIN
  2260.                         listInfoLen := SIZEOF (ProcessListInfoRec);
  2261.                         LGetCell (Ptr(@listInfo), (*◊*)listInfoLen, currCell,
  2262.                                 procList);
  2263.  
  2264.                         (* Kill the specified process *)
  2265.                         error := TerminateProcess (listInfo.serialNumber);
  2266.                         IF error <> noErr THEN
  2267.                             HandleError (rMiscErrMessages, kMiscErrUnknownMsg);
  2268.  
  2269.                         (* Go to the next cell *)
  2270.                         currCell.v := currCell.v + 1
  2271.                     END
  2272.             END
  2273.     END;
  2274.  
  2275. {$S Startup}
  2276. (*******************************************************************************
  2277. * Public: InitProcessGuts
  2278. *******************************************************************************)
  2279.  
  2280.     PROCEDURE InitProcessGuts;
  2281.     BEGIN
  2282.         gAppDAFilterUPP := NewFileFilterProc(@AppDAFilterProc);
  2283.         gProcessListLDEF := NewListDefProc(@ProcessListLDEF);
  2284.         gEqualPSNUPP := NewListSearchProc(ListSearchProcPtr(@EqualPSN));
  2285.     END;
  2286.     
  2287. END.
  2288.